// TODO: all called funcs should be in IRAM to work with disabled flash cache static void * esp_dbg_stubs_data_alloc(uint32_t size) { ESP_LOGV(TAG, "%s %d", __func__, size); void *p = malloc(size); ESP_LOGV(TAG, "%s EXIT %p", __func__, p); return p; }
esp_err_t sdmmc_send_cmd(sdmmc_card_t* card, sdmmc_command_t* cmd) { if (card->host.command_timeout_ms != 0) { cmd->timeout_ms = card->host.command_timeout_ms; } else if (cmd->timeout_ms == 0) { cmd->timeout_ms = SDMMC_DEFAULT_CMD_TIMEOUT_MS; } int slot = card->host.slot; ESP_LOGV(TAG, "sending cmd slot=%d op=%d arg=%x flags=%x data=%p blklen=%d datalen=%d timeout=%d", slot, cmd->opcode, cmd->arg, cmd->flags, cmd->data, cmd->blklen, cmd->datalen, cmd->timeout_ms); esp_err_t err = (*card->host.do_transaction)(slot, cmd); if (err != 0) { ESP_LOGD(TAG, "cmd=%d, sdmmc_req_run returned 0x%x", cmd->opcode, err); return err; } int state = MMC_R1_CURRENT_STATE(cmd->response); ESP_LOGV(TAG, "cmd response %08x %08x %08x %08x err=0x%x state=%d", cmd->response[0], cmd->response[1], cmd->response[2], cmd->response[3], cmd->error, state); return cmd->error; }
void Subscription::feed_data(MQTT_Packet data) { if(on_received == nullptr) return; if(data.topic.length() < topic.length()) return; std::string topicRest; int i=0; while(true) { if(topic.at(i) == '#') { topicRest = std::string(data.topic.data() + i, data.topic.length() - i); break; } if(topic.at(i) != data.topic.at(i)) return; i++; if(i == topic.length()) { if(i != data.topic.length()) return; else break; } } ESP_LOGV(mqtt_tag, "Topic %s matched! (Topic-Rest:%s)", topic.data(), topicRest.data()); on_received({topicRest, data.data}); }
esp_err_t WL_Ext_Perf::erase_sector_fit(uint32_t start_sector, uint32_t count) { ESP_LOGV(TAG, "%s begin, start_sector = 0x%08x, count = %i", __func__, start_sector, count); // This method works with one flash device sector and able to erase "count" of fatfs sectors from this sector esp_err_t result = ESP_OK; uint32_t pre_check_start = start_sector % this->size_factor; for (int i = 0; i < this->size_factor; i++) { if ((i < pre_check_start) || (i >= count + pre_check_start)) { result = this->read(start_sector / this->size_factor * this->flash_sector_size + i * this->fat_sector_size, &this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)], this->fat_sector_size); WL_EXT_RESULT_CHECK(result); } } result = WL_Flash::erase_sector(start_sector / this->size_factor); // erase comlete flash sector WL_EXT_RESULT_CHECK(result); // And write back only data that should not be erased... for (int i = 0; i < this->size_factor; i++) { if ((i < pre_check_start) || (i >= count + pre_check_start)) { result = this->write(start_sector / this->size_factor * this->flash_sector_size + i * this->fat_sector_size, &this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)], this->fat_sector_size); WL_EXT_RESULT_CHECK(result); } } return ESP_OK; }
static void spiffs_api_check(spiffs *fs, spiffs_check_type type, spiffs_check_report report, uint32_t arg1, uint32_t arg2) { static const char * spiffs_check_type_str[3] = { "LOOKUP", "INDEX", "PAGE" }; static const char * spiffs_check_report_str[7] = { "PROGRESS", "ERROR", "FIX INDEX", "FIX LOOKUP", "DELETE ORPHANED INDEX", "DELETE PAGE", "DELETE BAD FILE" }; if (report != SPIFFS_CHECK_PROGRESS) { ESP_LOGE(TAG, "CHECK: type:%s, report:%s, %x:%x", spiffs_check_type_str[type], spiffs_check_report_str[report], arg1, arg2); } else { ESP_LOGV(TAG, "CHECK PROGRESS: report:%s, %x:%x", spiffs_check_report_str[report], arg1, arg2); } }
/** * @brief Take a semaphore. * Take a semaphore but return if we haven't obtained it in the given period of milliseconds. * @param [in] timeoutMs Timeout in milliseconds. * @param [in] owner The new owner (for debugging) * @return True if we took the semaphore. */ bool FreeRTOS::Semaphore::take(uint32_t timeoutMs, std::string owner) { ESP_LOGV(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str()); bool rc = false; if (m_usePthreads) { assert(false); // We apparently don't have a timed wait for pthreads. } else { rc = ::xSemaphoreTake(m_semaphore, timeoutMs / portTICK_PERIOD_MS) == pdTRUE; } m_owner = owner; if (rc) { ESP_LOGV(LOG_TAG, "Semaphore taken: %s", toString().c_str()); } else { ESP_LOGE(LOG_TAG, "Semaphore NOT taken: %s", toString().c_str()); } return rc; } // Semaphore::take
static int vfs_semihost_open(void* ctx, const char * path, int flags, int mode) { int fd = -1, host_err = 0; char *host_path; vfs_semihost_ctx_t *semi_ctx = ctx; ESP_LOGV(TAG, "%s: %p '%s 0x%x 0x%x'", __func__, semi_ctx, path, flags, mode); if (ctx_uses_abspath(semi_ctx)) { flags |= ESP_O_SEMIHOST_ABSPATH; host_path = malloc(strlen(semi_ctx->host_path)+strlen(path)+1); if(host_path == NULL) { errno = ENOMEM; return -1; } strcpy(host_path, semi_ctx->host_path); strcat(host_path, path); } else { host_path = (char *)path; } fd = generic_syscall(SYS_OPEN, (int)host_path, strlen(host_path), flags, mode, &host_err); if (ctx_uses_abspath(semi_ctx)) { free(host_path); } if (fd == -1) { errno = host_err; } return fd; }
void esp_dbg_stubs_init() { s_dbg_stubs_ctl_data.tramp_addr = (uint32_t)s_stub_code_buf; s_dbg_stubs_ctl_data.min_stack_addr = (uint32_t)s_stub_min_stack; s_dbg_stubs_ctl_data.data_alloc = (uint32_t)esp_dbg_stubs_data_alloc; s_dbg_stubs_ctl_data.data_free = (uint32_t)esp_dbg_stubs_data_free; s_stub_entry[ESP_DBG_STUB_CONTROL_DATA] = (uint32_t)&s_dbg_stubs_ctl_data; eri_write(ESP_DBG_STUBS_TRAX_REG, (uint32_t)s_stub_entry); ESP_LOGV(TAG, "%s stubs %x", __func__, eri_read(ESP_DBG_STUBS_TRAX_REG)); }
static off_t vfs_semihost_lseek(void* ctx, int fd, off_t size, int mode) { int ret = -1, host_err = 0; ESP_LOGV(TAG, "%s: %d %ld %d", __func__, fd, size, mode); ret = generic_syscall(SYS_SEEK, fd, size, mode, 0, &host_err); if (ret == -1) { errno = host_err; } return (off_t)ret; }
static int vfs_semihost_close(void* ctx, int fd) { int ret = -1, host_err = 0; ESP_LOGV(TAG, "%s: %d", __func__, fd); ret = generic_syscall(SYS_CLOSE, fd, 0, 0, 0, &host_err); if (ret == -1) { errno = host_err; } return ret; }
static esp_err_t sdmmc_send_cmd(sdmmc_card_t* card, sdmmc_command_t* cmd) { int slot = card->host.slot; ESP_LOGV(TAG, "sending cmd slot=%d op=%d arg=%x flags=%x data=%p blklen=%d datalen=%d", slot, cmd->opcode, cmd->arg, cmd->flags, cmd->data, cmd->blklen, cmd->datalen); esp_err_t err = (*card->host.do_transaction)(slot, cmd); if (err != 0) { ESP_LOGD(TAG, "sdmmc_req_run returned 0x%x", err); return err; } int state = MMC_R1_CURRENT_STATE(cmd->response); ESP_LOGV(TAG, "cmd response %08x %08x %08x %08x err=0x%x state=%d", cmd->response[0], cmd->response[1], cmd->response[2], cmd->response[3], cmd->error, state); return cmd->error; }
/** * @brief Wait for a semaphore to be released by trying to take it and * then releasing it again. * @param [in] owner A debug tag. * @return The value associated with the semaphore. */ uint32_t FreeRTOS::Semaphore::wait(std::string owner) { ESP_LOGV(LOG_TAG, ">> wait: Semaphore waiting: %s for %s", toString().c_str(), owner.c_str()); if (m_usePthreads) { pthread_mutex_lock(&m_pthread_mutex); } else { xSemaphoreTake(m_semaphore, portMAX_DELAY); } m_owner = owner; if (m_usePthreads) { pthread_mutex_unlock(&m_pthread_mutex); } else { xSemaphoreGive(m_semaphore); } ESP_LOGV(LOG_TAG, "<< wait: Semaphore released: %s", toString().c_str()); m_owner = std::string("<N/A>"); return m_value; } // wait
static ssize_t vfs_semihost_read(void* ctx, int fd, void* data, size_t size) { int host_err = 0; size_t ret = -1; ESP_LOGV(TAG, "%s: %d %u bytes", __func__, fd, size); ret = generic_syscall(SYS_READ, fd, (int)data, size, 0, &host_err); if (ret == -1) { errno = host_err; } return (ssize_t)ret; }
/** * @brief Give a semaphore. * The Semaphore is given. */ void FreeRTOS::Semaphore::give() { ESP_LOGV(LOG_TAG, "Semaphore giving: %s", toString().c_str()); if (m_usePthreads) { pthread_mutex_unlock(&m_pthread_mutex); } else { xSemaphoreGive(m_semaphore); } // #ifdef ARDUINO_ARCH_ESP32 // FreeRTOS::sleep(10); // #endif m_owner = std::string("<N/A>"); } // Semaphore::give
esp_err_t esp_flash_encrypt_check_and_update(void) { uint32_t efuse_blk0 = REG_READ(EFUSE_BLK0_RDATA0_REG); ESP_LOGV(TAG, "efuse_blk0 raw value %08x", efuse_blk0); uint32_t flash_crypt_cnt = (efuse_blk0 & EFUSE_RD_FLASH_CRYPT_CNT_M) >> EFUSE_RD_FLASH_CRYPT_CNT_S; bool flash_crypt_wr_dis = efuse_blk0 & EFUSE_WR_DIS_FLASH_CRYPT_CNT; ESP_LOGV(TAG, "efuse FLASH_CRYPT_CNT 0x%x WR_DIS_FLASH_CRYPT_CNT 0x%x", flash_crypt_cnt, flash_crypt_wr_dis); if (__builtin_parity(flash_crypt_cnt) == 1) { /* Flash is already encrypted */ int left = (7 - __builtin_popcount(flash_crypt_cnt)) / 2; if (flash_crypt_wr_dis) { left = 0; /* can't update FLASH_CRYPT_CNT, no more flashes */ } ESP_LOGI(TAG, "flash encryption is enabled (%d plaintext flashes left)", left); return ESP_OK; } else { /* Flash is not encrypted, so encrypt it! */ return encrypt_flash_contents(flash_crypt_cnt, flash_crypt_wr_dis); } }
static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, esp_phy_calibration_data_t* out_cal_data) { esp_err_t err; uint32_t cal_data_version; err = nvs_get_u32(handle, PHY_CAL_VERSION_KEY, &cal_data_version); if (err != ESP_OK) { ESP_LOGD(TAG, "%s: failed to get cal_version (0x%x)", __func__, err); return err; } uint32_t cal_format_version = phy_get_rf_cal_version() & (~BIT(16)); ESP_LOGV(TAG, "phy_get_rf_cal_version: %d\n", cal_format_version); if (cal_data_version != cal_format_version) { ESP_LOGD(TAG, "%s: expected calibration data format %d, found %d", __func__, cal_format_version, cal_data_version); return ESP_FAIL; } uint8_t cal_data_mac[6]; size_t length = sizeof(cal_data_mac); err = nvs_get_blob(handle, PHY_CAL_MAC_KEY, cal_data_mac, &length); if (err != ESP_OK) { ESP_LOGD(TAG, "%s: failed to get cal_mac (0x%x)", __func__, err); return err; } if (length != sizeof(cal_data_mac)) { ESP_LOGD(TAG, "%s: invalid length of cal_mac (%d)", __func__, length); return ESP_ERR_INVALID_SIZE; } uint8_t sta_mac[6]; esp_efuse_mac_get_default(sta_mac); if (memcmp(sta_mac, cal_data_mac, sizeof(sta_mac)) != 0) { ESP_LOGE(TAG, "%s: calibration data MAC check failed: expected " \ MACSTR ", found " MACSTR, __func__, MAC2STR(sta_mac), MAC2STR(cal_data_mac)); return ESP_FAIL; } length = sizeof(*out_cal_data); err = nvs_get_blob(handle, PHY_CAL_DATA_KEY, out_cal_data, &length); if (err != ESP_OK) { ESP_LOGE(TAG, "%s: failed to get cal_data(0x%x)", __func__, err); return err; } if (length != sizeof(*out_cal_data)) { ESP_LOGD(TAG, "%s: invalid length of cal_data (%d)", __func__, length); return ESP_ERR_INVALID_SIZE; } return ESP_OK; }
static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, const esp_phy_calibration_data_t* cal_data) { esp_err_t err; uint32_t cal_format_version = phy_get_rf_cal_version() & (~BIT(16)); ESP_LOGV(TAG, "phy_get_rf_cal_version: %d\n", cal_format_version); err = nvs_set_u32(handle, PHY_CAL_VERSION_KEY, cal_format_version); if (err != ESP_OK) { return err; } uint8_t sta_mac[6]; esp_efuse_mac_get_default(sta_mac); err = nvs_set_blob(handle, PHY_CAL_MAC_KEY, sta_mac, sizeof(sta_mac)); if (err != ESP_OK) { return err; } err = nvs_set_blob(handle, PHY_CAL_DATA_KEY, cal_data, sizeof(*cal_data)); return err; }
static void set_cache_and_start_app( uint32_t drom_addr, uint32_t drom_load_addr, uint32_t drom_size, uint32_t irom_addr, uint32_t irom_load_addr, uint32_t irom_size, uint32_t entry_addr) { ESP_LOGD(TAG, "configure drom and irom and start"); Cache_Read_Disable( 0 ); Cache_Flush( 0 ); /* Clear the MMU entries that are already set up, so the new app only has the mappings it creates. */ for (int i = 0; i < DPORT_FLASH_MMU_TABLE_SIZE; i++) { DPORT_PRO_FLASH_MMU_TABLE[i] = DPORT_FLASH_MMU_TABLE_INVALID_VAL; } uint32_t drom_page_count = (drom_size + 64*1024 - 1) / (64*1024); // round up to 64k ESP_LOGV(TAG, "d mmu set paddr=%08x vaddr=%08x size=%d n=%d", drom_addr & 0xffff0000, drom_load_addr & 0xffff0000, drom_size, drom_page_count ); int rc = cache_flash_mmu_set( 0, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count ); ESP_LOGV(TAG, "rc=%d", rc ); rc = cache_flash_mmu_set( 1, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count ); ESP_LOGV(TAG, "rc=%d", rc ); uint32_t irom_page_count = (irom_size + 64*1024 - 1) / (64*1024); // round up to 64k ESP_LOGV(TAG, "i mmu set paddr=%08x vaddr=%08x size=%d n=%d", irom_addr & 0xffff0000, irom_load_addr & 0xffff0000, irom_size, irom_page_count ); rc = cache_flash_mmu_set( 0, 0, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count ); ESP_LOGV(TAG, "rc=%d", rc ); rc = cache_flash_mmu_set( 1, 0, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count ); ESP_LOGV(TAG, "rc=%d", rc ); DPORT_REG_CLR_BIT( DPORT_PRO_CACHE_CTRL1_REG, (DPORT_PRO_CACHE_MASK_IRAM0) | (DPORT_PRO_CACHE_MASK_IRAM1 & 0) | (DPORT_PRO_CACHE_MASK_IROM0 & 0) | DPORT_PRO_CACHE_MASK_DROM0 | DPORT_PRO_CACHE_MASK_DRAM1 ); DPORT_REG_CLR_BIT( DPORT_APP_CACHE_CTRL1_REG, (DPORT_APP_CACHE_MASK_IRAM0) | (DPORT_APP_CACHE_MASK_IRAM1 & 0) | (DPORT_APP_CACHE_MASK_IROM0 & 0) | DPORT_APP_CACHE_MASK_DROM0 | DPORT_APP_CACHE_MASK_DRAM1 ); Cache_Read_Enable( 0 ); // Application will need to do Cache_Flush(1) and Cache_Read_Enable(1) ESP_LOGD(TAG, "start: 0x%08x", entry_addr); typedef void (*entry_t)(void) __attribute__((noreturn)); entry_t entry = ((entry_t) entry_addr); // TODO: we have used quite a bit of stack at this point. // use "movsp" instruction to reset stack back to where ROM stack starts. (*entry)(); }
esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data, esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data) { assert((s_phy_rf_init_count <= 1) && (s_phy_rf_init_count >= 0)); _lock_acquire(&s_phy_rf_init_lock); if (s_phy_rf_init_count == 0) { // Enable WiFi/BT common peripheral clock periph_module_enable(PERIPH_WIFI_BT_COMMON_MODULE); ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d", init_data, calibration_data, mode); phy_set_wifi_mode_only(0); register_chipv7_phy(init_data, calibration_data, mode); coex_bt_high_prio(); } else { #if CONFIG_SW_COEXIST_ENABLE coex_init(); #endif } s_phy_rf_init_count++; _lock_release(&s_phy_rf_init_lock); return ESP_OK; }
static void esp_dbg_stubs_data_free(void *addr) { ESP_LOGV(TAG, "%s %p", __func__, addr); free(addr); ESP_LOGV(TAG, "%s EXIT %p", __func__, addr); }
esp_err_t WL_Ext_Perf::erase_range(size_t start_address, size_t size) { esp_err_t result = ESP_OK; if ((start_address % this->fat_sector_size) != 0) { result = ESP_ERR_INVALID_ARG; } if (((size % this->fat_sector_size) != 0) || (size == 0)) { result = ESP_ERR_INVALID_ARG; } WL_EXT_RESULT_CHECK(result); // The range to erase could be allocated in any possible way // --------------------------------------------------------- // | | | | | // |0|0|x|x|x|x|x|x|x|x|x|x|x|x|0|0| // | pre | rest | rest | post | <- check ranges // // Pre check - the data that is not fit to the full sector at the begining of the erased block // Post check - the data that are not fit to the full sector at the end of the erased block // rest - data that are fit to the flash device sector at the middle of the erased block // // In case of pre and post check situations the data of the non erased area have to be readed first and then // stored back. // For the rest area this operation not needed because complete flash device sector will be erased. ESP_LOGV(TAG, "%s begin, addr = 0x%08x, size = %i", __func__, start_address, size); // Calculate pre check values uint32_t pre_check_start = (start_address / this->fat_sector_size) % this->size_factor; uint32_t sectors_count = size / this->fat_sector_size; uint32_t pre_check_count = (this->size_factor - pre_check_start); if (pre_check_count > sectors_count) { pre_check_count = sectors_count; } // Calculate post ckeck uint32_t post_check_count = (sectors_count - pre_check_count) % this->size_factor; uint32_t post_check_start = ((start_address + size - post_check_count * this->fat_sector_size) / this->fat_sector_size); // Calculate rest uint32_t rest_check_count = sectors_count - pre_check_count - post_check_count; if ((pre_check_count == this->size_factor) && (0 == pre_check_start)) { rest_check_count+=this->size_factor; pre_check_count = 0; } uint32_t rest_check_start = start_address + pre_check_count * this->fat_sector_size; // Here we will clear pre_check_count amount of sectors if (pre_check_count != 0) { result = this->erase_sector_fit(start_address / this->fat_sector_size, pre_check_count); WL_EXT_RESULT_CHECK(result); } ESP_LOGV(TAG, "%s rest_check_start = %i, pre_check_count=%i, rest_check_count=%i, post_check_count=%i\n", __func__, rest_check_start, pre_check_count, rest_check_count, post_check_count); if (rest_check_count > 0) { rest_check_count = rest_check_count / this->size_factor; size_t start_sector = rest_check_start / this->flash_sector_size; for (size_t i = 0; i < rest_check_count; i++) { result = WL_Flash::erase_sector(start_sector + i); WL_EXT_RESULT_CHECK(result); } } if (post_check_count != 0) { result = this->erase_sector_fit(post_check_start, post_check_count); WL_EXT_RESULT_CHECK(result); } return ESP_OK; }
esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card) { ESP_LOGD(TAG, "%s", __func__); memset(card, 0, sizeof(*card)); memcpy(&card->host, config, sizeof(*config)); esp_err_t err = sdmmc_send_cmd_go_idle_state(card); if (err != ESP_OK) { ESP_LOGE(TAG, "%s: go_idle_state (1) returned 0x%x", __func__, err); return err; } ets_delay_us(10000); uint32_t host_ocr = get_host_ocr(config->io_voltage); err = sdmmc_send_cmd_send_if_cond(card, host_ocr); if (err == ESP_OK) { ESP_LOGD(TAG, "SDHC/SDXC card"); host_ocr |= SD_OCR_SDHC_CAP; } else if (err == ESP_ERR_TIMEOUT) { ESP_LOGD(TAG, "CMD8 timeout; not an SDHC/SDXC card"); } else { ESP_LOGE(TAG, "%s: send_if_cond (1) returned 0x%x", __func__, err); return err; } err = sdmmc_send_cmd_send_op_cond(card, host_ocr, &card->ocr); if (err != ESP_OK) { ESP_LOGE(TAG, "%s: send_op_cond (1) returned 0x%x", __func__, err); return err; } host_ocr &= card->ocr; ESP_LOGD(TAG, "sdmmc_card_init: host_ocr=%08x, card_ocr=%08x", host_ocr, card->ocr); err = sddmc_send_cmd_all_send_cid(card, &card->cid); if (err != ESP_OK) { ESP_LOGE(TAG, "%s: all_send_cid returned 0x%x", __func__, err); return err; } err = sdmmc_send_cmd_set_relative_addr(card, &card->rca); if (err != ESP_OK) { ESP_LOGE(TAG, "%s: set_relative_addr returned 0x%x", __func__, err); return err; } err = sdmmc_send_cmd_send_csd(card, &card->csd); if (err != ESP_OK) { ESP_LOGE(TAG, "%s: send_csd returned 0x%x", __func__, err); return err; } const size_t max_sdsc_capacity = UINT32_MAX / card->csd.sector_size + 1; if (!(card->ocr & SD_OCR_SDHC_CAP) && card->csd.capacity > max_sdsc_capacity) { ESP_LOGW(TAG, "%s: SDSC card reports capacity=%u. Limiting to %u.", __func__, card->csd.capacity, max_sdsc_capacity); card->csd.capacity = max_sdsc_capacity; } err = sdmmc_send_cmd_select_card(card); if (err != ESP_OK) { ESP_LOGE(TAG, "%s: select_card returned 0x%x", __func__, err); return err; } if ((card->ocr & SD_OCR_SDHC_CAP) == 0) { err = sdmmc_send_cmd_set_blocklen(card, &card->csd); if (err != ESP_OK) { ESP_LOGE(TAG, "%s: set_blocklen returned 0x%x", __func__, err); return err; } } err = sdmmc_send_cmd_send_scr(card, &card->scr); if (err != ESP_OK) { ESP_LOGE(TAG, "%s: send_scr returned 0x%x", __func__, err); return err; } if ((config->flags & SDMMC_HOST_FLAG_4BIT) && (card->scr.bus_width & SCR_SD_BUS_WIDTHS_4BIT)) { ESP_LOGD(TAG, "switching to 4-bit bus mode"); err = sdmmc_send_cmd_set_bus_width(card, 4); if (err != ESP_OK) { ESP_LOGE(TAG, "set_bus_width failed"); return err; } err = (*config->set_bus_width)(config->slot, 4); if (err != ESP_OK) { ESP_LOGE(TAG, "slot->set_bus_width failed"); return err; } uint32_t status; err = sdmmc_send_cmd_stop_transmission(card, &status); if (err != ESP_OK) { ESP_LOGE(TAG, "stop_transmission failed (0x%x)", err); return err; } } uint32_t status = 0; while (!(status & MMC_R1_READY_FOR_DATA)) { // TODO: add some timeout here uint32_t count = 0; err = sdmmc_send_cmd_send_status(card, &status); if (err != ESP_OK) { return err; } if (++count % 10 == 0) { ESP_LOGV(TAG, "waiting for card to become ready (%d)", count); } } if (config->max_freq_khz >= SDMMC_FREQ_HIGHSPEED && card->csd.tr_speed / 1000 >= SDMMC_FREQ_HIGHSPEED) { ESP_LOGD(TAG, "switching to HS bus mode"); err = (*config->set_card_clk)(config->slot, SDMMC_FREQ_HIGHSPEED); if (err != ESP_OK) { ESP_LOGE(TAG, "failed to switch peripheral to HS bus mode"); return err; } } else if (config->max_freq_khz >= SDMMC_FREQ_DEFAULT && card->csd.tr_speed / 1000 >= SDMMC_FREQ_DEFAULT) { ESP_LOGD(TAG, "switching to DS bus mode"); err = (*config->set_card_clk)(config->slot, SDMMC_FREQ_DEFAULT); if (err != ESP_OK) { ESP_LOGE(TAG, "failed to switch peripheral to HS bus mode"); return err; } } sdmmc_scr_t scr_tmp; err = sdmmc_send_cmd_send_scr(card, &scr_tmp); if (err != ESP_OK) { ESP_LOGE(TAG, "%s: send_scr returned 0x%x", __func__, err); return err; } if (memcmp(&card->scr, &scr_tmp, sizeof(scr_tmp)) != 0) { ESP_LOGE(TAG, "data check fail!"); return ESP_ERR_INVALID_RESPONSE; } return ESP_OK; }