首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >ESP32 SD卡速度问题

ESP32 SD卡速度问题
EN

Stack Overflow用户
提问于 2019-03-20 04:25:05
回答 1查看 1.1K关注 0票数 0

我正在尝试在Wrover套件上使用SD卡,但似乎速度是电路板本身的大问题。

起初我想从网上下载文件并将其保存到SD卡,但它花费了太长时间,所以为了测试它,我编写了一个循环,将一些字符保存到文件中,并在SD卡上创建大约1MB的大文件,这将花费很长时间。

~1MB文件可能是一个如此长的任务的原因。

为了完成这项任务,我已经将两个示例合并为一个。此外,我已经对所有内容进行了注释,并且只留下了部分写入文件来演示问题。

代码语言:javascript
复制
    /* ESP HTTP Client Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#define LOG_LOCAL_LEVEL ESP_LOG_ERROR 

#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "app_wifi.h"

#include "esp_http_client.h"


/* SD CARD */
#include "esp_vfs_fat.h"
#include "driver/sdmmc_host.h"
#include "driver/sdspi_host.h"
#include "sdmmc_cmd.h"
/* SD CARD */


#define USE_SPI_MODE
#ifdef USE_SPI_MODE
// Pin mapping when using SPI mode.
// With this mapping, SD card can be used both in SPI and 1-line SD mode.
// Note that a pull-up on CS line is required in SD mode.
#define PIN_NUM_MISO 2
#define PIN_NUM_MOSI 15
#define PIN_NUM_CLK  14
#define PIN_NUM_CS   13
#endif //USE_SPI_MODE



//#define MAX_HTTP_RECV_BUFFER 512
#define MAX_HTTP_RECV_BUFFER 1024
static const char *TAG = "HTTP_CLIENT";

// ------------------ GLOBAL VARS -----------------------------

FILE *fp=NULL;
// ------------------ GLOBAL VARS -----------------------------


/* Root cert for howsmyssl.com, taken from howsmyssl_com_root_cert.pem

   The PEM file was extracted from the output of this command:
   openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null

   The CA root cert is the last cert given in the chain of certs.

   To embed it in the app binary, the PEM file is named
   in the component.mk COMPONENT_EMBED_TXTFILES variable.
*/
extern const char howsmyssl_com_root_cert_pem_start[] asm("_binary_howsmyssl_com_root_cert_pem_start");
extern const char howsmyssl_com_root_cert_pem_end[]   asm("_binary_howsmyssl_com_root_cert_pem_end");

esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
    switch(evt->event_id) {
        case HTTP_EVENT_ERROR:
            ESP_LOGE (TAG, "HTTP_EVENT_ERROR");
            break;
        case HTTP_EVENT_ON_CONNECTED:
            ESP_LOGE (TAG, "HTTP_EVENT_ON_CONNECTED");
            break;
        case HTTP_EVENT_HEADER_SENT:
            ESP_LOGE (TAG, "HTTP_EVENT_HEADER_SENT");
            break;
        case HTTP_EVENT_ON_HEADER:
            ESP_LOGE (TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);

            break;
        case HTTP_EVENT_ON_DATA:
            ESP_LOGE (TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
            if (!esp_http_client_is_chunked_response(evt->client)) {
                // Write out data
                // printf("%.*s", evt->data_len, (char*)evt->data);

                if(fp == NULL){
                    fp = fopen("/sdcard/muzika.mp3","wb");
                }

                if(fp != NULL){
                    fwrite(evt->data,1,evt->data_len,fp);
                    ESP_LOGE (TAG, "---------- HTTP_EVENT_ON_DATA - WRITING TO SD CARD ----------");
                }

            }

            break;
        case HTTP_EVENT_ON_FINISH:
            ESP_LOGE (TAG, "HTTP_EVENT_ON_FINISH");

            fclose(fp);
            fp = NULL;

            break;
        case HTTP_EVENT_DISCONNECTED:
            ESP_LOGE (TAG, "HTTP_EVENT_DISCONNECTED");
            break;
    }
    return ESP_OK;
}


static void http_download_chunk()
{
    esp_http_client_config_t config = {
        //.url = "http://httpbin.org/stream-bytes/8912",
        .url = "http://www.theoctopusproject.com/mp3/whatthey.mp3",
        .event_handler = _http_event_handler,
    };
    esp_http_client_handle_t client = esp_http_client_init(&config);
    esp_err_t err = esp_http_client_perform(client);

    if (err == ESP_OK) {
        ESP_LOGI(TAG, "HTTP chunk encoding Status = %d, content_length = %d",
                esp_http_client_get_status_code(client),
                esp_http_client_get_content_length(client));
    } else {
        ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
    }
    esp_http_client_cleanup(client);
}



static void http_test_task(void *pvParameters)
{
    app_wifi_wait_connected();
    ESP_LOGI(TAG, "Connected to AP, begin http example");

    http_download_chunk();

    ESP_LOGI(TAG, "Finish http example");
    vTaskDelete(NULL);
}

void app_main()
{
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);
    // -- app_wifi_initialise();

    /* SDCARD SETUP */
    #ifndef USE_SPI_MODE
    ESP_LOGI(TAG, "Using SDMMC peripheral");
    sdmmc_host_t host = SDMMC_HOST_DEFAULT();

    // This initializes the slot without card detect (CD) and write protect (WP) signals.
    // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
    sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();

    // To use 1-line SD mode, uncomment the following line:
    // slot_config.width = 1;

    // GPIOs 15, 2, 4, 12, 13 should have external 10k pull-ups.
    // Internal pull-ups are not sufficient. However, enabling internal pull-ups
    // does make a difference some boards, so we do that here.
    gpio_set_pull_mode(15, GPIO_PULLUP_ONLY);   // CMD, needed in 4- and 1- line modes
    gpio_set_pull_mode(2, GPIO_PULLUP_ONLY);    // D0, needed in 4- and 1-line modes
    gpio_set_pull_mode(4, GPIO_PULLUP_ONLY);    // D1, needed in 4-line mode only
    gpio_set_pull_mode(12, GPIO_PULLUP_ONLY);   // D2, needed in 4-line mode only
    gpio_set_pull_mode(13, GPIO_PULLUP_ONLY);   // D3, needed in 4- and 1-line modes

#else
    ESP_LOGI(TAG, "Using SPI peripheral");

    sdmmc_host_t host = SDSPI_HOST_DEFAULT();
    sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT();
    slot_config.gpio_miso = PIN_NUM_MISO;
    slot_config.gpio_mosi = PIN_NUM_MOSI;
    slot_config.gpio_sck  = PIN_NUM_CLK;
    slot_config.gpio_cs   = PIN_NUM_CS;
    // This initializes the slot without card detect (CD) and write protect (WP) signals.
    // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
#endif //USE_SPI_MODE

    // Options for mounting the filesystem.
    // If format_if_mount_failed is set to true, SD card will be partitioned and
    // formatted in case when mounting fails.
    esp_vfs_fat_sdmmc_mount_config_t mount_config = {
        .format_if_mount_failed = false,
        .max_files = 5,
        .allocation_unit_size = 16 * 1024
    };

    // Use settings defined above to initialize SD card and mount FAT filesystem.
    // Note: esp_vfs_fat_sdmmc_mount is an all-in-one convenience function.
    // Please check its source code and implement error recovery when developing
    // production applications.
    sdmmc_card_t* card;
    ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);

    if (ret != ESP_OK) {
        if (ret == ESP_FAIL) {
            ESP_LOGE(TAG, "Failed to mount filesystem. "
                "If you want the card to be formatted, set format_if_mount_failed = true.");
        } else {
            ESP_LOGE(TAG, "Failed to initialize the card (%s). "
                "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
        }
        return;
    }

    // Card has been initialized, print its properties
    sdmmc_card_print_info(stdout, card);


    // Use POSIX and C standard library functions to work with files.
    // First create a file.
    ESP_LOGE(TAG, "Opening file");
    FILE* f = fopen("/sdcard/hello.txt", "w");
    if (f == NULL) {
        ESP_LOGE(TAG, "Failed to open file for writing");
        return;
    }


    // ------------------------ WRITE INTO FILE -------------------


    int j=0;
    for(int i = 0 ; i < 1048576  ; i++,j++){
    //fprintf(f, "Hello %s!\n", card->cid.name);
        fprintf(f, "X");
        if(j > 1024){
            vTaskDelay(3);
            j = 0;
        }
    }
    fclose(f);
    ESP_LOGE(TAG, "File written");

    // ------------------------ WRITE INTO FILE -------------------


    //-- xTaskCreate(&http_test_task, "http_test_task", 8192, NULL, 5, NULL);
    //xTaskCreate(&http_test_task, "http_test_task", 16384, NULL, 5, NULL);
}
EN

回答 1

Stack Overflow用户

发布于 2019-03-20 10:48:25

您的示例是一次写入一个字节。这不会让你对SD卡的整体写入速度有一个准确的概念--你的代码将花费不成比例的时间来处理单个写入。

如果您想更准确地了解写入存储卡的速度,请尝试一次写入1024字节(甚至更多)。衡量最大吞吐量和对性能敏感的应用程序的基准测试将始终一次写入尽可能多的数据,以便最大限度地减少写入开销。

此外,如果可能的话,不要使用fprintf()。它有额外的开销,因为它解析格式字符串。试试fwrite() -它的开销更小,让你更好地了解在最好的情况下你可以期待什么。

试试下面这样的代码:

代码语言:javascript
复制
char *buf = malloc(1024);

if(buf) {
  for(int i = 0; i < 1024; i++) {
    fwrite(buf, 1, 1024, f);
    vTaskDelay(3);  // you'll speed this up if you can omit this
  }

  ESP_LOGE(TAG, "File written");
  free(buf);
} else
  ESP_LOGE(TAG, "malloc() failed");

fclose(f);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55249423

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档