Merge branch 'bugfix/sdspi_example_esp32s3' into 'master'

examples: sdspi: re-enable for ESP32-S3, add Kconfig options for pins

Closes IDF-4641

See merge request espressif/esp-idf!17067
This commit is contained in:
Ivan Grokhotkov 2022-03-04 18:42:53 +08:00
commit c8b43ee0c1
16 changed files with 450 additions and 359 deletions

View File

@ -22,8 +22,10 @@ typedef int sdspi_dev_handle_t;
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
#define SDSPI_DEFAULT_HOST HSPI_HOST
#define SDSPI_DEFAULT_DMA SDSPI_DEFAULT_HOST
#else
#define SDSPI_DEFAULT_HOST SPI2_HOST
#define SDSPI_DEFAULT_DMA SPI_DMA_CH_AUTO
#endif
/**
@ -216,7 +218,7 @@ typedef struct {
.gpio_miso = GPIO_NUM_2, \
.gpio_mosi = GPIO_NUM_15, \
.gpio_sck = GPIO_NUM_14, \
.dma_channel = 1, \
.dma_channel = SDSPI_DEFAULT_DMA, \
}
/**

View File

@ -1,53 +1,96 @@
| Supported Targets | ESP32 | ESP32-S2 | ESP32-C3 |
| ----------------- | ----- | -------- | -------- |
# Simple HTTP File Server Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
If the SD card option is enabled, you can access files in the SD card by the path `/sdcard`
HTTP file server example demonstrates file serving with both upload and download capability, using the `esp_http_server` component of ESP-IDF. This example can use one of the following options for data storage:
HTTP file server example demonstrates file serving with both upload and download capability, using the `esp_http_server` component of ESP-IDF. The following URIs are provided by the server:
- SPIFFS filesystem in SPI Flash. This option works on any ESP development board without any extra hardware.
- FAT filesystem on an SD card. Both SDSPI and SDMMC drivers are supported. You need a development board with an SD card slot to use this option.
The following URIs are provided by the server:
| URI | Method | Description |
|----------------------|---------|-------------------------------------------------------------------------------------------|
|`index.html` | GET | Redirects to `/` |
|`favicon.ico` | GET | Browsers use this path to retrieve page icon which is embedded in flash |
|`/` | GET | Responds with webpage displaying list of files on SPIFFS and form for uploading new files |
|`/<file path>` | GET | For downloading files stored on SPIFFS |
|`/upload/<file path>` | POST | For uploading files on to SPIFFS. Files are sent as body of HTTP post requests |
|`/delete/<file path>` | POST | Command for deleting a file from SPIFFS |
|`/` | GET | Responds with webpage displaying list of files on the filesystem and form for uploading new files |
|`/<file path>` | GET | For downloading files stored on the filesystem |
|`/upload/<file path>` | POST | For uploading files on to the filesystem. Files are sent as body of HTTP post requests |
|`/delete/<file path>` | POST | Command for deleting a file from the filesystem |
File server implementation can be found under `main/file_server.c` which uses SPIFFS for file storage. `main/upload_script.html` has some HTML, JavaScript and Ajax content used for file uploading, which is embedded in the flash image and used as it is when generating the home page of the file server.
File server implementation can be found under `main/file_server.c`. `main/upload_script.html` has some HTML, JavaScript and Ajax content used for file uploading, which is embedded in the flash image and used as it is when generating the home page of the file server.
## Note
Note that the default `/index.html` and `/favicon.ico` files can be overridden by uploading files with same name to the filesystem.
`/index.html` and `/favicon.ico` can be overridden by uploading files with same pathname to SPIFFS.
## How to use the example
## Usage
### Wi-Fi/Ethernet connection
```
idf.py menuconfig
```
Open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
* Open the project configuration menu (`idf.py menuconfig`) go to `Example Configuration` ->
1. WIFI SSID: WIFI network to which your PC is also connected to.
2. WIFI Password: WIFI password
### SD card (optional)
* In order to test the file server demo :
1. compile and burn the firmware `idf.py -p PORT flash`
2. run `idf.py -p PORT monitor` and note down the IP assigned to your ESP module. The default port is 80
3. test the example interactively on a web browser (assuming IP is 192.168.43.130):
1. open path `http://192.168.43.130/` or `http://192.168.43.130/index.html` to see an HTML web page with list of files on the server (initially empty)
2. use the file upload form on the webpage to select and upload a file to the server
3. click a file link to download / open the file on browser (if supported)
4. click the delete link visible next to each file entry to delete them
4. test the example using curl (assuming IP is 192.168.43.130):
1. `myfile.html` is uploaded to `/path/on/device/myfile_copy.html` using `curl -X POST --data-binary @myfile.html 192.168.43.130:80/upload/path/on/device/myfile_copy.html`
2. download the uploaded copy back : `curl 192.168.43.130:80/path/on/device/myfile_copy.html > myfile_copy.html`
3. compare the copy with the original using `cmp myfile.html myfile_copy.html`
By default the example uses SPIFFS filesystem in SPI flash for file storage.
* To write to SD card, you need to:
1. Select the `Mount the SD card to the filesystem` in the configuration menu (by calling `idf.py menuconfig` and select the `EXAMPLE_MOUNT_SD_CARD` option.
2. If you need to format the card while the card fails to be mounted, enable the config option `The card will be formatted if mount has failed` (`EXAMPLE_FORMAT_SDCARD_IF_MOUNT_FAILED`). Be careful, all the data in the card will disappear.
To use an SD card for file storage instead, open the project configuration menu (`idf.py menuconfig`) and enter "File_serving example menu". Then enable "Use SD card for file storage" (`CONFIG_EXAMPLE_MOUNT_SD_CARD`) option.
SD cards can be used either over SPI interface (on all ESP chips) or over SDMMC interface (on ESP32 and ESP32-S3). To use SDMMC interface, enable "Use SDMMC host" (`CONFIG_EXAMPLE_USE_SDMMC_HOST`) option. To use SPI interface, disable this option.
GPIO pins used to connect the SD card can be configured for the SPI interface (on all chips), or for SDMMC interface on chips where it uses GPIO matrix (ESP32-S3). This can be done in "SD card pin configuration" submenu.
The example will be able to mount only cards formatted using FAT32 filesystem. If the card is formatted as exFAT or some other filesystem, you have an option to format it in the example code — "Format the card if mount failed" (`CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED`).
For more information on pin configuration for SDMMC and SDSPI, check related examples: [sdmmc](../../../storage/sd_card/sdmmc/README.md), [sdspi](../../../storage/sd_card/sdmmc/README.md).
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
### Working with the example
1. Note down the IP assigned to your ESP module. The IP address is logged by the example as follows:
```
I (5424) example_connect: - IPv4 address: 192.168.1.100
I (5424) example_connect: - IPv6 address: fe80:0000:0000:0000:86f7:03ff:fec0:1620, type: ESP_IP6_ADDR_IS
```
The following steps assume that IP address 192.168.1.100 was assigned.
2. Test the example interactively in a web browser. The default port is 80.
1. Open path http://192.168.1.100/ or http://192.168.1.100/index.html to see an HTML page with list of files on the server. The page will initially be empty.
2. Use the file upload form on the webpage to select and upload a file to the server.
3. Click a file link to download / open the file on browser (if supported).
4. Click the delete link visible next to each file entry to delete them.
3. Test the example using curl:
1. `myfile.html` can be uploaded to `/path/on/device/myfile_copy.html` using:
```
curl -X POST --data-binary @myfile.html 192.168.43.130:80/upload/path/on/device/myfile_copy.html
```
2. Download the uploaded file back:
```
curl 192.168.43.130:80/path/on/device/myfile_copy.html > myfile_copy.html`
```
3. Compare the copy with the original using `cmp myfile.html myfile_copy.html`
Note: You will have to access the SD card by SPI bus with sdspi driver, if you are using ESP32S2.
## Note

View File

@ -1,18 +1,7 @@
#!/usr/bin/env python
#
# Copyright 2021 Espressif Systems (Shanghai) CO LTD
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import hashlib
import http.client
@ -26,9 +15,9 @@ from tiny_test_fw import Utility
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols')
def test_examples_protocol_http_server_file_serving(env, extra_data): # type: (tiny_test_fw.Env.Env, None) -> None # pylint: disable=unused-argument
def test_examples_protocol_http_server_file_serving(env, _): # type: (tiny_test_fw.Env.Env, None) -> None
# Acquire DUT
dut1 = env.get_dut('http file_serving', 'examples/protocols/http_server/file_serving', dut_class=ttfw_idf.ESP32DUT)
dut1 = env.get_dut('http file_serving', 'examples/protocols/http_server/file_serving', dut_class=ttfw_idf.ESP32DUT, app_config_name='spiffs')
# Get binary file
binary_file = os.path.join(dut1.app.binary_path, 'file_server.bin')
@ -41,11 +30,11 @@ def test_examples_protocol_http_server_file_serving(env, extra_data): # type: (
Utility.console_log('Starting http file serving simple test app')
dut1.start_app()
dut1.expect('Initializing SPIFFS', timeout=30)
# Parse IP address of STA
Utility.console_log('Waiting to connect with AP')
got_ip = dut1.expect(re.compile(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)'), timeout=30)[0]
# Expected logs
dut1.expect('Initializing SPIFFS', timeout=30)
got_port = dut1.expect(re.compile(r"Starting HTTP Server on port: '(\d+)'"), timeout=30)[0]
Utility.console_log('Got IP : ' + got_ip)
Utility.console_log('Got Port : ' + got_port)
@ -91,7 +80,7 @@ def test_examples_protocol_http_server_file_serving(env, extra_data): # type: (
Utility.console_log("\nTesting the upload of \"already existing\" file on the file server")
client.postreq(conn, '/upload/' + str(upload_file_name), data=None)
try:
dut1.expect('File already exists : /spiffs/' + str(upload_file_name), timeout=10)
dut1.expect('File already exists : /data/' + str(upload_file_name), timeout=10)
except Exception:
Utility.console_log('Failed the test for uploading existing file on the file server')
raise
@ -136,7 +125,7 @@ def test_examples_protocol_http_server_file_serving(env, extra_data): # type: (
download_data = client.getreq(conn, '/' + str(upload_file_name))
try:
dut1.expect('Failed to stat file : /spiffs/' + str(upload_file_name), timeout=10)
dut1.expect('Failed to stat file : /data/' + str(upload_file_name), timeout=10)
except Exception:
Utility.console_log('Failed the test to download non existing file from the file server')
raise
@ -144,4 +133,4 @@ def test_examples_protocol_http_server_file_serving(env, extra_data): # type: (
if __name__ == '__main__':
test_examples_protocol_http_server_file_serving() # pylint: disable=no-value-for-parameter
test_examples_protocol_http_server_file_serving()

View File

@ -1,3 +1,3 @@
idf_component_register(SRCS "main.c" "file_server.c"
idf_component_register(SRCS "main.c" "file_server.c" "mount.c"
INCLUDE_DIRS "."
EMBED_FILES "favicon.ico" "upload_script.html")

View File

@ -1,13 +1,13 @@
menu "Http_File_Serving Example menu"
menu "HTTP file_serving example menu"
config EXAMPLE_MOUNT_SD_CARD
bool "Mount the SD card to the filesystem"
bool "Use SD card for file storage"
default n
help
If this config item is set, the file you upload to server can be chosen to save in the SDcard.
config EXAMPLE_FORMAT_IF_MOUNT_SDCARD_FAILED
bool "The card will be formatted if mount has failed."
bool "Format the card if mount failed"
default n
depends on EXAMPLE_MOUNT_SD_CARD
help
@ -16,11 +16,79 @@ menu "Http_File_Serving Example menu"
config EXAMPLE_USE_SDMMC_HOST
bool "Use SDMMC host"
default y
depends on EXAMPLE_MOUNT_SD_CARD && IDF_TARGET_ESP32
depends on EXAMPLE_MOUNT_SD_CARD && SOC_SDMMC_HOST_SUPPORTED
help
If this config item is set, SDMMC is used to mount the SDcard.
Otherwise, will use SPI host to access and mount the SDcard.
menu "SD card pin configuration (SPI)"
depends on EXAMPLE_MOUNT_SD_CARD && !EXAMPLE_USE_SDMMC_HOST
config EXAMPLE_PIN_MOSI
int "MOSI GPIO number"
default 15 if IDF_TARGET_ESP32
default 35 if IDF_TARGET_ESP32S2
default 35 if IDF_TARGET_ESP32S3
default 4 # C3 and others
config EXAMPLE_PIN_MISO
int "MISO GPIO number"
default 2 if IDF_TARGET_ESP32
default 37 if IDF_TARGET_ESP32S2
default 37 if IDF_TARGET_ESP32S3
default 6 # C3 and others
config EXAMPLE_PIN_CLK
int "CLK GPIO number"
default 14 if IDF_TARGET_ESP32
default 36 if IDF_TARGET_ESP32S2
default 36 if IDF_TARGET_ESP32S3
default 5 # C3 and others
config EXAMPLE_PIN_CS
int "CS GPIO number"
default 13 if IDF_TARGET_ESP32
default 34 if IDF_TARGET_ESP32S2
default 34 if IDF_TARGET_ESP32S3
default 1 # C3 and others
endmenu
menu "SD card pin configuration (SDMMC)"
depends on EXAMPLE_USE_SDMMC_HOST && SOC_SDMMC_USE_GPIO_MATRIX
config EXAMPLE_PIN_CMD
int "CMD GPIO number"
default 35 if IDF_TARGET_ESP32S3
default 1
config EXAMPLE_PIN_CLK
int "CLK GPIO number"
default 36 if IDF_TARGET_ESP32S3
default 2
config EXAMPLE_PIN_D0
int "D0 GPIO number"
default 37 if IDF_TARGET_ESP32S3
default 3
config EXAMPLE_PIN_D1
int "D1 GPIO number"
default 38 if IDF_TARGET_ESP32S3
default 4
config EXAMPLE_PIN_D2
int "D2 GPIO number"
default 33 if IDF_TARGET_ESP32S3
default 5
config EXAMPLE_PIN_D3
int "D3 GPIO number"
default 34 if IDF_TARGET_ESP32S3
default 6
endmenu
config EXAMPLE_HTTPD_CONN_CLOSE_HEADER
bool "Send connection close header from request handlers"
default y

View File

@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* HTTP File Server Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
@ -443,16 +448,10 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
}
/* Function to start the file server */
esp_err_t start_file_server(const char *base_path)
esp_err_t example_start_file_server(const char *base_path)
{
static struct file_server_data *server_data = NULL;
/* Validate file storage base path */
if (!base_path || strcmp(base_path, "/spiffs") != 0) {
ESP_LOGE(TAG, "File server presently supports only '/spiffs' as base path");
return ESP_ERR_INVALID_ARG;
}
if (server_data) {
ESP_LOGE(TAG, "File server already started");
return ESP_ERR_INVALID_STATE;

View File

@ -0,0 +1,30 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* HTTP File Server Example, common declarations
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.
*/
#pragma once
#include "sdkconfig.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
esp_err_t example_mount_storage(const char *base_path);
esp_err_t example_start_file_server(const char *base_path);
#ifdef __cplusplus
}
#endif

View File

@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* HTTP File Server Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
@ -7,239 +12,39 @@
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include <sys/param.h>
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_spiffs.h"
#include "esp_netif.h"
#include "esp_err.h"
#include "esp_vfs_fat.h"
#include "nvs_flash.h"
#include "protocol_examples_common.h"
#include "sdkconfig.h"
#include "driver/sdspi_host.h"
#include "driver/spi_common.h"
#include "sdmmc_cmd.h"
#include "soc/soc_caps.h"
#if SOC_SDMMC_HOST_SUPPORTED
#include "driver/sdmmc_host.h"
#endif
#include "file_serving_example_common.h"
/* This example demonstrates how to create file server
* using esp_http_server. This file has only startup code.
* Look in file_server.c for the implementation */
* Look in file_server.c for the implementation.
*/
#define MOUNT_POINT "/sdcard"
static const char *TAG="example";
/* ESP32-S2/C3 doesn't have an SD Host peripheral, always use SPI,
* ESP32 can choose SPI or SDMMC Host, SPI is used by default: */
#ifndef CONFIG_EXAMPLE_USE_SDMMC_HOST
#define USE_SPI_MODE
#endif
// DMA channel to be used by the SPI peripheral
#if CONFIG_IDF_TARGET_ESP32
#define SPI_DMA_CHAN 1
// on ESP32-S2, DMA channel must be the same as host id
#elif CONFIG_IDF_TARGET_ESP32S2
#define SPI_DMA_CHAN host.slot
#elif CONFIG_IDF_TARGET_ESP32C3
// on ESP32-C3, DMA channels are shared with all other peripherals
#define SPI_DMA_CHAN 1
#endif //CONFIG_IDF_TARGET_ESP32
// When testing SD and SPI modes, keep in mind that once the card has been
// initialized in SPI mode, it can not be reinitialized in SD mode without
// toggling power to the card.
#ifdef CONFIG_EXAMPLE_MOUNT_SD_CARD
static sdmmc_card_t* mount_card = NULL;
static char * mount_base_path = MOUNT_POINT;
#endif
#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.
#if CONFIG_IDF_TARGET_ESP32C3
#define PIN_NUM_MISO 2
#define PIN_NUM_MOSI 7
#define PIN_NUM_CLK 6
#define PIN_NUM_CS 10
#else
#define PIN_NUM_MISO 2
#define PIN_NUM_MOSI 15
#define PIN_NUM_CLK 14
#define PIN_NUM_CS 13
#endif // CONFIG_IDF_TARGET_ESP32C3
#endif //USE_SPI_MODE
/* Function to initialize SPIFFS */
static esp_err_t init_spiffs(void)
{
ESP_LOGI(TAG, "Initializing SPIFFS");
esp_vfs_spiffs_conf_t conf = {
.base_path = "/spiffs",
.partition_label = NULL,
.max_files = 5, // This decides the maximum number of files that can be created on the storage
.format_if_mount_failed = true
};
esp_err_t ret = esp_vfs_spiffs_register(&conf);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount or format filesystem");
} else if (ret == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "Failed to find SPIFFS partition");
} else {
ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
}
return ESP_FAIL;
}
size_t total = 0, used = 0;
ret = esp_spiffs_info(NULL, &total, &used);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret));
return ESP_FAIL;
}
ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
return ESP_OK;
}
/* Declare the function which starts the file server.
* Implementation of this function is to be found in
* file_server.c */
esp_err_t start_file_server(const char *base_path);
#ifdef CONFIG_EXAMPLE_MOUNT_SD_CARD
void sdcard_mount(void)
{
/*sd_card part code*/
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
#ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED
.format_if_mount_failed = true,
#else
.format_if_mount_failed = false,
#endif // EXAMPLE_FORMAT_IF_MOUNT_FAILED
.max_files = 5,
.allocation_unit_size = 16 * 1024
};
sdmmc_card_t* card;
const char mount_point[] = MOUNT_POINT;
ESP_LOGI(TAG, "Initializing SD card");
#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
esp_err_t ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);
#else
ESP_LOGI(TAG, "Using SPI peripheral");
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
spi_bus_config_t bus_cfg = {
.mosi_io_num = PIN_NUM_MOSI,
.miso_io_num = PIN_NUM_MISO,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
esp_err_t ret = spi_bus_initialize(host.slot, &bus_cfg, SPI_DMA_CHAN);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize bus.");
ESP_ERROR_CHECK(ret);
}
// 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.
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
slot_config.gpio_cs = PIN_NUM_CS;
slot_config.host_id = host.slot;
ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card);
mount_card = card;
#endif //USE_SPI_MODE
if(ret != ESP_OK){
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem. "
"If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
} 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));
}
ESP_ERROR_CHECK(ret);
}
sdmmc_card_print_info(stdout, card);
}
static esp_err_t unmount_card(const char* base_path, sdmmc_card_t* card)
{
#ifdef USE_SPI_MODE
esp_err_t err = esp_vfs_fat_sdcard_unmount(base_path, card);
#else
esp_err_t err = esp_vfs_fat_sdmmc_unmount();
#endif
ESP_ERROR_CHECK(err);
#ifdef USE_SPI_MODE
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
err = spi_bus_free(host.slot);
#endif
ESP_ERROR_CHECK(err);
return err;
}
#endif //CONFIG_EXAMPLE_MOUNT_SD_CARD
static const char *TAG = "example";
void app_main(void)
{
/*Mount the SDcard first if needed.*/
#ifdef CONFIG_EXAMPLE_MOUNT_SD_CARD
sdcard_mount();
#endif
ESP_LOGI(TAG, "Starting example");
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* Initialize file storage */
const char* base_path = "/data";
ESP_ERROR_CHECK(example_mount_storage(base_path));
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
/* Initialize file storage */
ESP_ERROR_CHECK(init_spiffs());
/* Start the file server */
ESP_ERROR_CHECK(start_file_server("/spiffs"));
#ifdef CONFIG_EXAMPLE_MOUNT_SD_CARD
//deinitialize the bus after all devices are removed
ESP_ERROR_CHECK(unmount_card(mount_base_path, mount_card));
#endif
ESP_ERROR_CHECK(example_start_file_server(base_path));
ESP_LOGI(TAG, "File server started");
}

View File

@ -0,0 +1,160 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* HTTP File Server Example, SD card / SPIFFS mount functions.
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.
*/
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "esp_err.h"
#include "esp_vfs_fat.h"
#include "esp_spiffs.h"
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "driver/sdspi_host.h"
#include "driver/spi_common.h"
#if SOC_SDMMC_HOST_SUPPORTED
#include "driver/sdmmc_host.h"
#endif
#include "sdmmc_cmd.h"
#include "file_serving_example_common.h"
static const char *TAG = "example_mount";
#ifdef CONFIG_EXAMPLE_MOUNT_SD_CARD
esp_err_t example_mount_storage(const char* base_path)
{
ESP_LOGI(TAG, "Initializing SD card");
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
#ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_SDCARD_FAILED
.format_if_mount_failed = true,
#else
.format_if_mount_failed = false,
#endif // CONFIG_EXAMPLE_FORMAT_IF_MOUNT_SDCARD_FAILED
.max_files = 5,
.allocation_unit_size = 16 * 1024
};
esp_err_t ret;
sdmmc_card_t* card;
#ifdef CONFIG_EXAMPLE_USE_SDMMC_HOST
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, change this to 1:
slot_config.width = 4;
#ifdef SOC_SDMMC_USE_GPIO_MATRIX
// For chips which support GPIO Matrix for SDMMC peripheral, specify the pins.
slot_config.clk = CONFIG_EXAMPLE_PIN_CLK;
slot_config.cmd = CONFIG_EXAMPLE_PIN_CMD;
slot_config.d0 = CONFIG_EXAMPLE_PIN_D0;
slot_config.d1 = CONFIG_EXAMPLE_PIN_D1;
slot_config.d2 = CONFIG_EXAMPLE_PIN_D2;
slot_config.d3 = CONFIG_EXAMPLE_PIN_D3;
#endif // SOC_SDMMC_USE_GPIO_MATRIX
// Enable internal pullups on enabled pins. The internal pullups
// are insufficient however, please make sure 10k external pullups are
// connected on the bus. This is for debug / example purpose only.
slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
ret = esp_vfs_fat_sdmmc_mount(base_path, &host, &slot_config, &mount_config, &card);
#else // CONFIG_EXAMPLE_USE_SDMMC_HOST
ESP_LOGI(TAG, "Using SPI peripheral");
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
spi_bus_config_t bus_cfg = {
.mosi_io_num = CONFIG_EXAMPLE_PIN_MOSI,
.miso_io_num = CONFIG_EXAMPLE_PIN_MISO,
.sclk_io_num = CONFIG_EXAMPLE_PIN_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
ret = spi_bus_initialize(host.slot, &bus_cfg, SDSPI_DEFAULT_DMA);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize bus.");
return ret;
}
// 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.
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
slot_config.gpio_cs = CONFIG_EXAMPLE_PIN_CS;
slot_config.host_id = host.slot;
ret = esp_vfs_fat_sdspi_mount(base_path, &host, &slot_config, &mount_config, &card);
#endif // !CONFIG_EXAMPLE_USE_SDMMC_HOST
if (ret != ESP_OK){
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem. "
"If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
} 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 ret;
}
sdmmc_card_print_info(stdout, card);
return ESP_OK;
}
#else // CONFIG_EXAMPLE_MOUNT_SD_CARD
/* Function to initialize SPIFFS */
esp_err_t example_mount_storage(const char* base_path)
{
ESP_LOGI(TAG, "Initializing SPIFFS");
esp_vfs_spiffs_conf_t conf = {
.base_path = base_path,
.partition_label = NULL,
.max_files = 5, // This sets the maximum number of files that can be open at the same time
.format_if_mount_failed = true
};
esp_err_t ret = esp_vfs_spiffs_register(&conf);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount or format filesystem");
} else if (ret == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "Failed to find SPIFFS partition");
} else {
ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
}
return ret;
}
size_t total = 0, used = 0;
ret = esp_spiffs_info(NULL, &total, &used);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret));
return ret;
}
ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
return ESP_OK;
}
#endif // !CONFIG_EXAMPLE_MOUNT_SD_CARD

View File

@ -1,3 +0,0 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"

View File

@ -1,3 +1,2 @@
CONFIG_EXAMPLE_MOUNT_SD_CARD=y
CONFIG_EXAMPLE_FORMAT_IF_MOUNT_SDCARD_FAILED=y
CONFIG_EXAMPLE_USE_SDMMC_HOST=y

View File

@ -1,11 +1,8 @@
| Supported Targets | ESP32 | ESP32-S2 | ESP32-C3 |
| ----------------- | ----- | -------- | -------- |
# SD Card example (SDSPI)
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates how to use an SD card with an ESP device. Example does the following steps:
This example demonstrates how to use an SD card with an ESP device over an SPI interface. Example does the following steps:
1. Use an "all-in-one" `esp_vfs_fat_sdspi_mount` function to:
- initialize SDSPI peripheral,
@ -21,44 +18,48 @@ This example support SD (SDSC, SDHC, SDXC) cards.
## Hardware
Pins can be customized. See the initialization of ``spi_bus_config_t`` and ``sdspi_slot_config_t`` structures in the example code.
This example requires a development board with an SD card socket and and SD card.
Although it is possible to connect an SD card breakout adapter, keep in mind that connections using breakout cables are often unreliable and have poor signal integrity. You may need to use lower clock frequency when working with SD card breakout adapters.
It is recommended to get familiar with [the document about pullup requirements](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/sd_pullup_requirements.html) to understand Pullup/down resistor support and compatibility of various ESP modules and development boards.
### Pin assignments
The GPIO pin numbers used to connect an SD card can be customized. This can be done in two ways:
1. Using menuconfig: Run `idf.py menuconfig` in the project directory and open "SD SPI Example Configuration" menu.
2. In the source code: See the initialization of ``spi_bus_config_t`` and ``sdspi_slot_config_t`` structures in the example code.
This example doesn't utilize card detect (CD) and write protect (WP) signals from SD card slot.
### Connections for ESP32
The table below shows the default pin assignments.
This example runs on ESP-WROVER-KIT boards without any extra modifications required, only the SD card needs to be inserted into the slot.
SD card pin | SPI pin | ESP32 pin | ESP32-S2, ESP32-S3 | ESP32-C3 and other chips | Notes
------------|---------|---------------|--------------------|---------------------------|-------------
D0 | MISO | GPIO2 | GPIO37 | GPIO6 |
D3 | CS | GPIO13 (MTCK) | GPIO34 | GPIO1 |
CLK | SCK | GPIO14 (MTMS) | GPIO36 | GPIO5 |
CMD | MOSI | GPIO15 (MTDO) | GPIO35 | GPIO4 | 10k pullup
Other ESP32 development boards need to be connected to SD card as follows:
ESP32 pin | SD card pin | SPI pin | Notes
--------------|-------------|---------|------------
GPIO2 | D0 | MISO |
GPIO13 (MTCK) | D3 | CS |
GPIO14 (MTMS) | CLK | SCK |
GPIO15 (MTDO) | CMD | MOSI | 10k pullup
#### ESP32 related notes
With the default pin assignments, this example runs on ESP-WROVER-KIT boards without any extra modifications required. Only the SD card needs to be inserted into the slot.
For other development boards, adjust the pin assignments as explained above.
Some boards require specific manipulation to enable UART Download mode (GPIO2 low) - eg ESP32-Azure IoT Kit needs KEY_IO0 pressed down for the time of firmware flashing operation (sets IO0 and IO2 low). See troubleshooting section for more details
### Connections for ESP32S2
#### ESP32-S2 and ESP32-S3 related notes
ESP32S2 pin | SD card pin | SPI pin | Notes
--------------|-------------|---------|------------
GPIO37 | D0 | MISO |
GPIO34 | D3 | CS |
GPIO36 | CLK | SCK |
GPIO35 | CMD | MOSI | 10k pullup
With the default pin assignments, this example is compatible ESP32-S2-USB-OTG and ESP32-S3-USB-OTG development boards.
### Connections for ESP32-C3
For other development boards, adjust the pin assignments as explained above.
ESP32-C3 pin | SD card pin | SPI pin | Notes
--------------|-------------|---------|------------
GPIO5 | CLK | SCK |
GPIO4 | CMD | MOSI | 10k pullup
GPIO6 | D0 | MISO |
GPIO1 | D3 | CS |
#### Notes for ESP32-C3 and other chips
Espressif doesn't offer development boards with an SD card slot for these chips. Please check the pin assignments and adjust them for your board if necessary. The process to change pin assignments is described above.
### Build and flash
@ -77,7 +78,7 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui
## Example output
Here is an example console output. In this case a 128MB SDSC card was connected, and `EXAMPLE_FORMAT_IF_MOUNT_FAILED` menuconfig option enabled. Card was unformatted, so the initial mount has failed. Card was then partitioned, formatted, and mounted again.
Here is an example console output. In this case a 64GB SDHC card was connected, and `EXAMPLE_FORMAT_IF_MOUNT_FAILED` menuconfig option enabled. Card was unformatted, so the initial mount has failed. Card was then partitioned, formatted, and mounted again.
```
I (336) example: Initializing SD card
@ -103,25 +104,22 @@ I (7396) example: Card unmounted
### Failure to mount filesystem
```
example: Failed to mount filesystem. If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.
```
The example will be able to mount only cards formatted using FAT32 filesystem. If the card is formatted as exFAT or some other filesystem, you have an option to format it in the example code. Enable the `EXAMPLE_FORMAT_IF_MOUNT_FAILED` menuconfig option, then build and flash the example.
> The following error message is printed: `example: Failed to mount filesystem. If you want the card to be formatted, set the CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.`
The example will be able to mount only cards formatted using FAT32 filesystem. If the card is formatted as exFAT or some other filesystem, you have an option to format it in the example code. Enable the `CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED` menuconfig option, then build and flash the example.
### Unable to download the example BIN (or serial port not available)
```
After the first successful flashing of the example firmware, it is not possible to flash again.
(Download mode not activated when running idf.py (==esptool.py) or the board's serial port disappears completely)
```
### Unable to flash the example, or serial port not available (ESP32 only)
> After the first successful flashing of the example firmware, it is not possible to flash again. Download mode not activated when running `idf.py flash` or the board's serial port disappears completely.
Some ESP32 boards require specific handling to activate the download mode after a system reset, due to GPIO2 pin now being used as both SDSPI (MISO) and an active-low bootstrapping signal for entering download mode. For instance, the ESP32-Azure IoT Kit requires KEY_IO0 button to remain pressed during whole firmware flashing operation, as it sets both GPIO0 and GPIO2 signals low.
Some boards require specific handling to activate the Download mode after a system reset, due to GPIO2 pin now being used as both SDSPI (MISO) and a bootstrapping signal for enabling UART0 Boot (low).
(For instance, the ESP32-Azure IoT Kit requires KEY_IO0 button remain pressed during whole firmware flashing operation, as it sets both GPIO0 and GPIO2 signals low).
Check you board documentation/schematics for appropriate procedure.
An attempt to download a new firmware under this conditions may also result in the board's serial port disappearing from your PC device list - rebooting your computer should fix the issue. After your device is back, use
`esptool --port PORT --before no_reset --baud 115200 --chip esp32 erase_flash`
to clean your board's flash, then download your firmware properly.
to erase your board's flash, then flash the firmware again.

View File

@ -1,4 +1,4 @@
menu "SD Card Example menu"
menu "SD SPI Example Configuration"
config EXAMPLE_FORMAT_IF_MOUNT_FAILED
bool "Format the card if mount failed"
@ -6,4 +6,33 @@ menu "SD Card Example menu"
help
If this config item is set, format_if_mount_failed will be set to true and the card will be formatted if
the mount has failed.
config EXAMPLE_PIN_MOSI
int "MOSI GPIO number"
default 15 if IDF_TARGET_ESP32
default 35 if IDF_TARGET_ESP32S2
default 35 if IDF_TARGET_ESP32S3
default 4 # C3 and others
config EXAMPLE_PIN_MISO
int "MISO GPIO number"
default 2 if IDF_TARGET_ESP32
default 37 if IDF_TARGET_ESP32S2
default 37 if IDF_TARGET_ESP32S3
default 6 # C3 and others
config EXAMPLE_PIN_CLK
int "CLK GPIO number"
default 14 if IDF_TARGET_ESP32
default 36 if IDF_TARGET_ESP32S2
default 36 if IDF_TARGET_ESP32S3
default 5 # C3 and others
config EXAMPLE_PIN_CS
int "CS GPIO number"
default 13 if IDF_TARGET_ESP32
default 34 if IDF_TARGET_ESP32S2
default 34 if IDF_TARGET_ESP32S3
default 1 # C3 and others
endmenu

View File

@ -1,4 +1,6 @@
/* SD card and FAT filesystem example.
This example uses SPI peripheral to communicate with SD card.
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
@ -6,8 +8,6 @@
CONDITIONS OF ANY KIND, either express or implied.
*/
// This example uses SPI peripheral to communicate with SD card.
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
@ -18,37 +18,12 @@ static const char *TAG = "example";
#define MOUNT_POINT "/sdcard"
// Pin mapping
#if CONFIG_IDF_TARGET_ESP32
#define PIN_NUM_MISO 2
#define PIN_NUM_MOSI 15
#define PIN_NUM_CLK 14
#define PIN_NUM_CS 13
#elif CONFIG_IDF_TARGET_ESP32S2
// adapted for internal test board ESP-32-S3-USB-OTG-Ev-BOARD_V1.0 (with ESP32-S2-MINI-1 module)
#define PIN_NUM_MISO 37
#define PIN_NUM_MOSI 35
#define PIN_NUM_CLK 36
#define PIN_NUM_CS 34
#elif CONFIG_IDF_TARGET_ESP32C3
#define PIN_NUM_MISO 6
#define PIN_NUM_MOSI 4
#define PIN_NUM_CLK 5
#define PIN_NUM_CS 1
#endif //CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_IDF_TARGET_ESP32S2
#define SPI_DMA_CHAN host.slot
#elif CONFIG_IDF_TARGET_ESP32C3
#define SPI_DMA_CHAN SPI_DMA_CH_AUTO
#else
#define SPI_DMA_CHAN 1
#endif
// Pin assignments can be set in menuconfig, see "SD SPI Example Configuration" menu.
// You can also change the pin assignments here by changing the following 4 lines.
#define PIN_NUM_MISO CONFIG_EXAMPLE_PIN_MISO
#define PIN_NUM_MOSI CONFIG_EXAMPLE_PIN_MOSI
#define PIN_NUM_CLK CONFIG_EXAMPLE_PIN_CLK
#define PIN_NUM_CS CONFIG_EXAMPLE_PIN_CS
void app_main(void)
@ -86,7 +61,7 @@ void app_main(void)
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
ret = spi_bus_initialize(host.slot, &bus_cfg, SPI_DMA_CHAN);
ret = spi_bus_initialize(host.slot, &bus_cfg, SDSPI_DEFAULT_DMA);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize bus.");
return;
@ -104,7 +79,7 @@ void app_main(void)
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem. "
"If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
"If you want the card to be formatted, set the CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
} 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));

View File

@ -2293,9 +2293,6 @@ examples/protocols/http_server/captive_portal/example_test.py
examples/protocols/http_server/captive_portal/main/dns_server.c
examples/protocols/http_server/captive_portal/main/include/dns_server.h
examples/protocols/http_server/captive_portal/main/main.c
examples/protocols/http_server/file_serving/http_server_file_serving_test.py
examples/protocols/http_server/file_serving/main/file_server.c
examples/protocols/http_server/file_serving/main/main.c
examples/protocols/http_server/persistent_sockets/http_server_persistence_test.py
examples/protocols/http_server/persistent_sockets/main/main.c
examples/protocols/http_server/restful_server/main/esp_rest_main.c