/** * \brief Display basic information of the card. * \note This function should be called only after the card has been * initialized successfully. * * \param slot SD/MMC slot to test */ static void main_display_info_card(uint8_t slot) { printf("Card information:\n\r"); printf(" "); switch (sd_mmc_get_type(slot)) { case CARD_TYPE_SD | CARD_TYPE_HC: printf("SDHC"); break; case CARD_TYPE_SD: printf("SD"); break; case CARD_TYPE_MMC | CARD_TYPE_HC: printf("MMC High Density"); break; case CARD_TYPE_MMC: printf("MMC"); break; case CARD_TYPE_SDIO: printf("SDIO\n\r"); return; case CARD_TYPE_SD_COMBO: printf("SD COMBO"); break; case CARD_TYPE_UNKNOWN: default: printf("Unknown\n\r"); return; } printf("\n\r %d MB\n\r", (uint16_t)(sd_mmc_get_capacity(slot)/1024)); }
// Get information about the SD card and interface speed MassStorage::InfoResult MassStorage::GetCardInfo(size_t slot, uint64_t& capacity, uint64_t& freeSpace, uint32_t& speed, uint32_t& clSize) { if (slot >= NumSdCards) { return InfoResult::badSlot; } SdCardInfo& inf = info[slot]; if (!inf.isMounted) { return InfoResult::noCard; } capacity = (uint64_t)sd_mmc_get_capacity(slot) * 1024; speed = sd_mmc_get_interface_speed(slot); String<ShortScratchStringLength> path; path.printf("%u:/", slot); uint32_t freeClusters; FATFS *fs; const FRESULT fr = f_getfree(path.c_str(), &freeClusters, &fs); if (fr == FR_OK) { clSize = fs->csize * 512; freeSpace = (fr == FR_OK) ? (uint64_t)freeClusters * clSize : 0; } else { clSize = 0; freeSpace = 0; } return InfoResult::ok; }
/* Changes the encryption level of the drive. If encrypt is true: encrypt drive, else decrypt */ uint8_t sd_change_encryption(uint8_t slot, bool encrypt, bool change_key, uint8_t *old_passwd, uint8_t *new_passwd) { sd_mmc_err_t err; uint32_t i, nb_blocks; encrypt_config_t *config_ptr = NULL; security_get_config(&config_ptr); if ((encrypt == config_ptr->encryption_level) && !change_key) return CTRL_GOOD; if (change_key) { sha2(old_passwd, MAX_PASS_LENGTH, old_hash_cipher_key, 0); sha2(new_passwd, MAX_PASS_LENGTH, new_hash_cipher_key, 0); } if (old_hash_cipher_key == new_hash_cipher_key) return CTRL_GOOD; do { err = sd_mmc_check(slot); if ((SD_MMC_ERR_NO_CARD != err) && (SD_MMC_INIT_ONGOING != err) && (SD_MMC_OK != err)) { while (SD_MMC_ERR_NO_CARD != sd_mmc_check(slot)) { } } } while (SD_MMC_OK != err); nb_blocks = sd_mmc_get_capacity(slot) * (1024 / SD_MMC_BLOCK_SIZE); for (i = 0; i < nb_blocks / SD_BLOCKS_PER_ACCESS; ++i) { if (SD_MMC_OK != sd_mmc_init_read_blocks(slot, i, SD_BLOCKS_PER_ACCESS)) return CTRL_FAIL; if (SD_MMC_OK != sd_mmc_start_read_blocks(src_buf, SD_BLOCKS_PER_ACCESS)) return CTRL_FAIL; if (SD_MMC_OK != sd_mmc_wait_end_of_read_blocks()) return CTRL_FAIL; aes_set_key(&AVR32_AES, (unsigned int *)old_hash_cipher_key); ram_aes_ram(change_key ? false : encrypt, SD_MMC_BLOCK_SIZE * SD_BLOCKS_PER_ACCESS / sizeof(unsigned int), (unsigned int *)src_buf, (unsigned int *)dest_buf); if (change_key) { aes_set_key(&AVR32_AES, (unsigned int *)new_hash_cipher_key); ram_aes_ram(true, SD_MMC_BLOCK_SIZE * SD_BLOCKS_PER_ACCESS / sizeof(unsigned int), (unsigned int *)dest_buf, (unsigned int *)src_buf); } if (SD_MMC_OK != sd_mmc_init_write_blocks(slot, i, SD_BLOCKS_PER_ACCESS)) return CTRL_FAIL; if (SD_MMC_OK != sd_mmc_start_write_blocks(src_buf, SD_BLOCKS_PER_ACCESS)) return CTRL_FAIL; if (SD_MMC_OK != sd_mmc_wait_end_of_write_blocks()) return CTRL_FAIL; } return CTRL_GOOD; }
/** * \brief Card R/W tests * * \param slot SD/MMC slot to test */ static void main_test_memory(uint8_t slot) { uint32_t last_blocks_addr, i, nb_trans; REDTIMESTAMP tick_start; uint32_t time_ms; // Compute the last address last_blocks_addr = sd_mmc_get_capacity(slot) * (1024 / SD_MMC_BLOCK_SIZE); if (last_blocks_addr < (TEST_MEM_START_OFFSET / 512lu)) { printf("[Memory is too small.]\n\r"); return; } last_blocks_addr -= (TEST_MEM_START_OFFSET / SD_MMC_BLOCK_SIZE); printf("Card R/W test:\n\r"); // Read the last block printf(" Read... "); tick_start = RedOsTimestamp(); if (SD_MMC_OK != sd_mmc_init_read_blocks(slot, last_blocks_addr, TEST_MEM_AREA_SIZE / SD_MMC_BLOCK_SIZE)) { printf("[FAIL]\n\r"); return; } for (nb_trans = 0; nb_trans < (TEST_MEM_AREA_SIZE / TEST_MEM_ACCESS_SIZE); nb_trans++) { if (SD_MMC_OK != sd_mmc_start_read_blocks(buf_test, TEST_MEM_ACCESS_SIZE / SD_MMC_BLOCK_SIZE)) { printf("[FAIL]\n\r"); return; } if (SD_MMC_OK != sd_mmc_wait_end_of_read_blocks(false)) { printf("[FAIL]\n\r"); return; } } time_ms = RedOsTimePassed(tick_start) / 1000U; if (time_ms) { // Valid time_ms printf(" %d KBps ", (int)(((TEST_MEM_AREA_SIZE * 1000lu) / 1024lu) / time_ms)); } printf("[OK]\n\r"); if (sd_mmc_is_write_protected(slot)) { printf("Card is write protected [WRITE TEST SKIPPED]\n\r"); return; } // Fill buffer with a pattern for (i = 0; i < (TEST_MEM_ACCESS_SIZE / sizeof(uint32_t)); i++) { ((uint32_t*)buf_test)[i] = TEST_FILL_VALUE_U32; } printf(" Write pattern... "); if (SD_MMC_OK != sd_mmc_init_write_blocks(slot, last_blocks_addr, TEST_MEM_AREA_SIZE / SD_MMC_BLOCK_SIZE)) { printf("[FAIL]\n\r"); return; } tick_start = RedOsTimestamp(); for (nb_trans = 0; nb_trans < (TEST_MEM_AREA_SIZE / TEST_MEM_ACCESS_SIZE); nb_trans++) { ((uint32_t*)buf_test)[0] = nb_trans; // Unique value for each area if (SD_MMC_OK != sd_mmc_start_write_blocks(buf_test, TEST_MEM_ACCESS_SIZE / SD_MMC_BLOCK_SIZE)) { printf("[FAIL]\n\r"); return; } if (SD_MMC_OK != sd_mmc_wait_end_of_write_blocks(false)) { printf("[FAIL]\n\r"); return; } } time_ms = RedOsTimePassed(tick_start) / 1000U; if (time_ms) { // Valid time_ms printf(" %d KBps ", (int)(((TEST_MEM_AREA_SIZE * 1000lu) / 1024lu) / time_ms)); } printf("[OK]\n\r"); printf(" Read and check pattern... "); if (SD_MMC_OK != sd_mmc_init_read_blocks(slot, last_blocks_addr, TEST_MEM_AREA_SIZE / SD_MMC_BLOCK_SIZE)) { printf("Read [FAIL]\n\r"); return; } for (nb_trans = 0; nb_trans < (TEST_MEM_AREA_SIZE / TEST_MEM_ACCESS_SIZE); nb_trans++) { // Clear buffer for (i = 0; i < (TEST_MEM_ACCESS_SIZE / sizeof(uint32_t)); i++) { ((uint32_t*)buf_test)[i] = 0xFFFFFFFF; } // Fill buffer if (SD_MMC_OK != sd_mmc_start_read_blocks(buf_test, TEST_MEM_ACCESS_SIZE / SD_MMC_BLOCK_SIZE)) { printf("Read [FAIL]\n\r"); return; } if (SD_MMC_OK != sd_mmc_wait_end_of_read_blocks(false)) { printf("Read [FAIL]\n\r"); return; } // Check the unique value of the area if (((uint32_t*)buf_test)[0] != nb_trans) { printf("Check [FAIL]\n\r"); return; } // Check buffer for (i = 1; i < (TEST_MEM_ACCESS_SIZE / sizeof(uint32_t)); i++) { if (((uint32_t*)buf_test)[i] != TEST_FILL_VALUE_U32) { printf("Check [FAIL]\n\r"); return; } } } printf("[OK]\n\r"); }
/** * \brief SD/MMC card read and write test. * * \param test Current test case. */ static void run_sd_mmc_rw_test(const struct test_case *test) { uint32_t i; uint32_t last_blocks_addr; uint16_t nb_block, nb_trans; bool split_tansfer = false; /* Compute the last address */ last_blocks_addr = sd_mmc_get_capacity(0) * (1024/SD_MMC_BLOCK_SIZE) - 50; test_assert_true(test, last_blocks_addr > NB_MULTI_BLOCKS, "Error: SD/MMC capacity."); last_blocks_addr -= NB_MULTI_BLOCKS; nb_block = 1; run_sd_mmc_rw_test_next: /* Read (save blocks) the last blocks */ test_assert_true(test, SD_MMC_OK == sd_mmc_init_read_blocks(0, last_blocks_addr, nb_block), "Error: SD/MMC initialize read sector(s)."); for (nb_trans = 0; nb_trans < (split_tansfer? nb_block : 1); nb_trans++) { test_assert_true(test, SD_MMC_OK == sd_mmc_start_read_blocks( &buf_save[nb_trans * SD_MMC_BLOCK_SIZE], split_tansfer? 1 : nb_block), "Error: SD/MMC start read sector(s)."); test_assert_true(test, SD_MMC_OK == sd_mmc_wait_end_of_read_blocks(false), "Error: SD/MMC wait end of read sector(s)."); } test_assert_true(test, !sd_mmc_is_write_protected(0), "Error: SD/MMC is write protected."); /* Fill buffer */ for (i = 0; i < (SD_MMC_BLOCK_SIZE * nb_block / sizeof(uint32_t)); i++) { ((uint32_t*)buf_test)[i] = TEST_FILL_VALUE_U32; } /* Write the last blocks */ test_assert_true(test, SD_MMC_OK == sd_mmc_init_write_blocks(0, last_blocks_addr, nb_block), "Error: SD/MMC initialize write sector(s)."); for (nb_trans = 0; nb_trans < (split_tansfer? nb_block : 1); nb_trans++) { test_assert_true(test, SD_MMC_OK == sd_mmc_start_write_blocks( &buf_test[nb_trans * SD_MMC_BLOCK_SIZE], split_tansfer? 1 : nb_block), "Error: SD/MMC start write sector(s)."); test_assert_true(test, SD_MMC_OK == sd_mmc_wait_end_of_write_blocks(false), "Error: SD/MMC wait end of write sector(s)."); } /* Clean buffer */ for (i = 0; i < (SD_MMC_BLOCK_SIZE * nb_block / sizeof(uint32_t)); i++) { ((uint32_t*)buf_test)[i] = 0xFFFFFFFF; } /* Read the last block */ test_assert_true(test, SD_MMC_OK == sd_mmc_init_read_blocks(0, last_blocks_addr, nb_block), "Error: SD/MMC initialize read sector(s)."); for (nb_trans = 0; nb_trans < (split_tansfer? nb_block : 1); nb_trans++) { test_assert_true(test, SD_MMC_OK == sd_mmc_start_read_blocks( &buf_test[nb_trans * SD_MMC_BLOCK_SIZE], split_tansfer? 1 : nb_block), "Error: SD/MMC start read sector(s)."); test_assert_true(test, SD_MMC_OK == sd_mmc_wait_end_of_read_blocks(false), "Error: SD/MMC wait end of read sector(s)."); } /* Check buffer */ for (i = 0; i < (SD_MMC_BLOCK_SIZE * nb_block / sizeof(uint32_t)); i++) { test_assert_true(test, ((uint32_t*)buf_test)[i] == TEST_FILL_VALUE_U32, "Error: SD/MMC verify write operation."); } /* Write (restore) the last block */ test_assert_true(test, SD_MMC_OK == sd_mmc_init_write_blocks(0, last_blocks_addr, nb_block), "Error: SD/MMC initialize write restore sector(s)."); for (nb_trans = 0; nb_trans < (split_tansfer? nb_block : 1); nb_trans++) { test_assert_true(test, SD_MMC_OK == sd_mmc_start_write_blocks( &buf_save[nb_trans * SD_MMC_BLOCK_SIZE], split_tansfer? 1 : nb_block), "Error: SD/MMC start write restore sector(s)."); test_assert_true(test, SD_MMC_OK == sd_mmc_wait_end_of_write_blocks(false), "Error: SD/MMC wait end of write restore sector(s)."); } /* Read (check restore) the last block */ test_assert_true(test, SD_MMC_OK == sd_mmc_init_read_blocks(0, last_blocks_addr, nb_block), "Error: SD/MMC initialize read sector(s)."); for (nb_trans = 0; nb_trans < (split_tansfer? nb_block : 1); nb_trans++) { test_assert_true(test, SD_MMC_OK == sd_mmc_start_read_blocks( &buf_test[nb_trans * SD_MMC_BLOCK_SIZE], split_tansfer? 1 : nb_block), "Error: SD/MMC start read sector(s)."); test_assert_true(test, SD_MMC_OK == sd_mmc_wait_end_of_read_blocks(false), "Error: SD/MMC wait end of read sector(s)."); } /* Check buffer restored */ for (i = 0; i < (SD_MMC_BLOCK_SIZE * nb_block / sizeof(uint32_t)); i++) { test_assert_true(test, ((uint32_t*)buf_test)[i] == ((uint32_t*)buf_save)[i], "Error: SD/MMC verify restore operation."); } if (nb_block == 1) { /* Launch second test */ nb_block = NB_MULTI_BLOCKS; goto run_sd_mmc_rw_test_next; } if (!split_tansfer) { /* Launch third test */ split_tansfer = true; goto run_sd_mmc_rw_test_next; } }
Ctrl_status sd_mmc_read_capacity(uint8_t slot, uint32_t *nb_sector) { // Return last sector address (-1) *nb_sector = (sd_mmc_get_capacity(slot) * 2) - 1; return sd_mmc_test_unit_ready(slot); }
/** * \brief Show SD card status on the OLED screen. */ static void display_sd_info(void) { FRESULT res; uint8_t card_check; uint8_t sd_card_type; uint32_t sd_card_size; char size[64]; /* Is SD card present? */ if (gpio_pin_is_low(SD_MMC_0_CD_GPIO) == false) { multi_language_show_no_sd_info(); } else { multi_language_show_sd_info(); sd_mmc_init(); card_check = sd_mmc_check(0); while (card_check != SD_MMC_OK) { card_check = sd_mmc_check(0); delay_ms(1); } if (card_check == SD_MMC_OK) { sd_card_type = sd_mmc_get_type(0); sd_card_size = sd_mmc_get_capacity(0); /* Card type */ switch (sd_card_type) { case CARD_TYPE_SD: multi_language_show_normal_card_info(); break; case CARD_TYPE_SDIO: break; case CARD_TYPE_HC: multi_language_show_high_capacity_card_info(); break; case CARD_TYPE_SD_COMBO: break; default: multi_language_show_unknow_card_info(); } multi_language_show_card_size_info(size, sd_card_size); /* Try to mount file system. */ memset(&fs, 0, sizeof(FATFS)); res = f_mount(LUN_ID_SD_MMC_0_MEM, &fs); if (FR_INVALID_DRIVE == res) { multi_language_show_no_fatfs_info(); sd_fs_found = 0; } else { get_num_files_on_sd(); if (sd_num_files == 0) { multi_language_show_no_files_info(); sd_fs_found = 1; } else { multi_language_show_browse_info(); sd_fs_found = 1; } } } } }
/** * \brief Show SD card status on the OLED screen. */ static void display_sd_info(void) { uint8_t card_check; uint8_t sd_card_type; uint8_t sd_card_version; uint32_t sd_card_size; uint8_t size[10]; // Is SD card present? if (gpio_pin_is_low(SD_MMC_0_CD_GPIO) == false) { ssd1306_write_text("Please insert SD card..."); } else { ssd1306_write_text("SD card information:"); sd_mmc_init(); card_check = sd_mmc_check(0); while (card_check != SD_MMC_OK) { card_check = sd_mmc_check(0); delay_ms(1); } if (card_check == SD_MMC_OK) { sd_card_type = sd_mmc_get_type(0); sd_card_version = sd_mmc_get_version(0); sd_card_size = sd_mmc_get_capacity(0); ssd1306_set_page_address(1); ssd1306_set_column_address(0); // Card type switch(sd_card_type) { case CARD_TYPE_SD: ssd1306_write_text("- Type: Normal SD card"); break; case CARD_TYPE_SDIO: ssd1306_write_text("- Type: SDIO card"); break; case CARD_TYPE_HC: ssd1306_write_text("- Type: High Capacity card"); break; case CARD_TYPE_SD_COMBO: ssd1306_write_text("- Type: SDIO/Memory card"); break; default: ssd1306_write_text("- Type: unknown"); } ssd1306_set_page_address(2); ssd1306_set_column_address(0); // SD card version switch(sd_card_version) { case CARD_VER_SD_1_0: ssd1306_write_text("- Version: 1.0x"); break; case CARD_VER_SD_1_10: ssd1306_write_text("- Version: 1.10"); break; case CARD_VER_SD_2_0: ssd1306_write_text("- Version: 2.00"); break; case CARD_VER_SD_3_0: ssd1306_write_text("- Version: 3.0x"); break; default: ssd1306_write_text("- Version: unknown"); } ssd1306_set_page_address(3); ssd1306_set_column_address(0); sprintf(size, "- Total size: %lu KB", sd_card_size); ssd1306_write_text(size); } } }
// Mount the specified SD card, returning true if done, false if needs to be called again. // If an error occurs, return true with the error message in 'reply'. // This may only be called to mount one card at a time. GCodeResult MassStorage::Mount(size_t card, const StringRef& reply, bool reportSuccess) { if (card >= NumSdCards) { reply.copy("SD card number out of range"); return GCodeResult::error; } SdCardInfo& inf = info[card]; MutexLocker lock1(fsMutex); MutexLocker lock2(inf.volMutex); if (!inf.mounting) { if (inf.isMounted) { if (AnyFileOpen(&inf.fileSystem)) { // Don't re-mount the card if any files are open on it reply.copy("SD card has open file(s)"); return GCodeResult::error; } (void)InternalUnmount(card, false); } inf.mountStartTime = millis(); inf.mounting = true; delay(2); } if (inf.cardState == CardDetectState::notPresent) { reply.copy("No SD card present"); inf.mounting = false; return GCodeResult::error; } if (inf.cardState != CardDetectState::present) { return GCodeResult::notFinished; // wait for debounce to finish } const sd_mmc_err_t err = sd_mmc_check(card); if (err != SD_MMC_OK && millis() - inf.mountStartTime < 5000) { delay(2); return GCodeResult::notFinished; } inf.mounting = false; if (err != SD_MMC_OK) { reply.printf("Cannot initialise SD card %u: %s", card, TranslateCardError(err)); return GCodeResult::error; } // Mount the file systems const char path[3] = { (char)('0' + card), ':', 0 }; const FRESULT mounted = f_mount(&inf.fileSystem, path, 1); if (mounted != FR_OK) { reply.printf("Cannot mount SD card %u: code %d", card, mounted); return GCodeResult::error; } inf.isMounted = true; if (reportSuccess) { float capacity = ((float)sd_mmc_get_capacity(card) * 1024) / 1000000; // get capacity and convert from Kib to Mbytes const char* capUnits; if (capacity >= 1000.0) { capacity /= 1000; capUnits = "Gb"; } else { capUnits = "Mb"; } reply.printf("%s card mounted in slot %u, capacity %.2f%s", TranslateCardType(sd_mmc_get_type(card)), card, (double)capacity, capUnits); } return GCodeResult::ok; }