Skip to content

Commit

Permalink
Merge branch 'feat/add_sdio_interface' into 'master'
Browse files Browse the repository at this point in the history
feat: Add the SDIO inteface and esp port

Closes ESF-74

See merge request espressif/esp-serial-flasher!130
  • Loading branch information
DNedic committed Dec 12, 2024
2 parents 58480f9 + b74194b commit bcbc726
Show file tree
Hide file tree
Showing 21 changed files with 990 additions and 11 deletions.
3 changes: 2 additions & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ test_esp1:
script:
- cd $CI_PROJECT_DIR
- pytest --target=esp32s3 --port=/dev/serial_ports/ESP32S3_ESP32C3 -k 'not test_esp32_spi_load_ram_example'
- pytest --target=esp32 --port=/dev/serial_ports/ESP32_ESP32C6 -k 'test_esp32_sdio_load_ram_example'

test_esp2:
extends: .test_template
Expand All @@ -318,7 +319,7 @@ test_esp2:
- "build_master"
script:
- cd $CI_PROJECT_DIR
- pytest --target=esp32 --port=/dev/serial_ports/ESP32_ESP32
- pytest --target=esp32 --port=/dev/serial_ports/ESP32_ESP32 -k 'not test_esp32_sdio_load_ram_example'
- pytest --target=esp32s3 --port=/dev/serial_ports/ESP32S3_ESP32C3 -k 'not test_esp32_usb_cdc_acm_example'

test_stm32:
Expand Down
24 changes: 20 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
cmake_minimum_required(VERSION 3.5)

set(srcs
src/esp_targets.c
src/md5_hash.c
src/esp_loader.c
src/protocol_common.c
)
set(defs)

Expand Down Expand Up @@ -39,14 +37,17 @@ add_option(SERIAL_FLASHER_WRITE_BLOCK_RETRIES 3)
if (NOT DEFINED ESP_PLATFORM AND
NOT DEFINED SERIAL_FLASHER_INTERFACE_UART AND
NOT DEFINED SERIAL_FLASHER_INTERFACE_SPI AND
NOT DEFINED SERIAL_FLASHER_INTERFACE_USB)
NOT DEFINED SERIAL_FLASHER_INTERFACE_USB AND
NOT DEFINED SERIAL_FLASHER_INTERFACE_SDIO)

set(SERIAL_FLASHER_INTERFACE_UART true)
endif()

if (DEFINED SERIAL_FLASHER_INTERFACE_UART OR CONFIG_SERIAL_FLASHER_INTERFACE_UART STREQUAL "y")
list(APPEND srcs
src/esp_targets.c
src/esp_stubs.c
src/protocol_serial.c
src/protocol_uart.c
src/slip.c
)
Expand All @@ -62,7 +63,9 @@ if (DEFINED SERIAL_FLASHER_INTERFACE_UART OR CONFIG_SERIAL_FLASHER_INTERFACE_UAR

elseif(DEFINED SERIAL_FLASHER_INTERFACE_USB OR CONFIG_SERIAL_FLASHER_INTERFACE_USB STREQUAL "y")
list(APPEND srcs
src/esp_targets.c
src/esp_stubs.c
src/protocol_serial.c
src/protocol_uart.c
src/slip.c
)
Expand All @@ -75,11 +78,20 @@ elseif(DEFINED SERIAL_FLASHER_INTERFACE_USB OR CONFIG_SERIAL_FLASHER_INTERFACE_U

elseif(DEFINED SERIAL_FLASHER_INTERFACE_SPI OR CONFIG_SERIAL_FLASHER_INTERFACE_SPI STREQUAL "y")
list(APPEND srcs
src/esp_targets.c
src/protocol_serial.c
src/protocol_spi.c
)
list(APPEND defs
SERIAL_FLASHER_INTERFACE_SPI
)
elseif(DEFINED SERIAL_FLASHER_INTERFACE_SDIO OR CONFIG_SERIAL_FLASHER_INTERFACE_SDIO STREQUAL "y")
list(APPEND srcs
src/protocol_sdio.c
)
list(APPEND defs
SERIAL_FLASHER_INTERFACE_SDIO
)
endif()

if (DEFINED ESP_PLATFORM)
Expand All @@ -95,13 +107,17 @@ if (DEFINED ESP_PLATFORM)
list(APPEND srcs
port/esp32_usb_cdc_acm_port.c
)
elseif (${CONFIG_SERIAL_FLASHER_INTERFACE_SDIO})
list(APPEND srcs
port/esp32_sdio_port.c
)
endif()

# Register component to esp-idf build system
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS include port
PRIV_INCLUDE_DIRS private_include
PRIV_REQUIRES driver esp_timer)
PRIV_REQUIRES driver esp_timer sdmmc)

if (${CONFIG_SERIAL_FLASHER_INTERFACE_USB})
idf_component_set_property(${COMPONENT_NAME} PRIV_REQUIRES usb APPEND)
Expand Down
3 changes: 3 additions & 0 deletions Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ menu "ESP serial flasher"
config SERIAL_FLASHER_INTERFACE_USB
bool "USB"

config SERIAL_FLASHER_INTERFACE_SDIO
bool "SDIO (Experimental, Only supports downloading to RAM)"

endchoice

config SERIAL_FLASHER_RESET_HOLD_TIME_MS
Expand Down
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,17 @@ Supported **target** microcontrollers:

Supported hardware interfaces:
- UART
- SPI (only for RAM download)
- USB CDC ACM
- SPI (only for RAM download)
- SDIO (only for RAM download, experimental)

For example usage check the [examples](/examples) directory.

## Configuration

These are the configuration toggles available to the user:

* `SERIAL_FLASHER_INTERFACE_UART`/`SERIAL_FLASHER_INTERFACE_SPI`/`SERIAL_FLASHER_INTERFACE_USB`
* `SERIAL_FLASHER_INTERFACE_UART`/`SERIAL_FLASHER_INTERFACE_SPI`/`SERIAL_FLASHER_INTERFACE_USB/SERIAL_FLASHER_INTERFACE_SDIO`

This defines the hardware interface to use.

Expand Down Expand Up @@ -163,7 +164,11 @@ The port layer for the given host microcontroller can be implemented if not avai

For the SPI interface ports
- `loader_port_spi_set_cs()`
needs to be implemented as well.
needs to be implemented as well,

and
- `loader_port_sdio_card_init()`
for the SDIO interface ports.

The following functions are part of the [io.h](include/io.h) header for convenience, however, the user does not have to strictly follow function signatures, as there are not called directly from library.

Expand Down
18 changes: 18 additions & 0 deletions examples/esp32_sdio_load_ram_example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)

set(EXTRA_COMPONENT_DIRS ../../)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp32-sdio-ram-loader)

# There are issues with ESP-IDF 4.4 and -Wunused-parameter
if ("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "4.4")
idf_component_get_property(flasher esp-serial-flasher COMPONENT_LIB)

target_compile_options(${flasher}
PRIVATE
-Wunused-parameter
-Wshadow
)
endif()
77 changes: 77 additions & 0 deletions examples/esp32_sdio_load_ram_example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Example of loading the program into RAM through SDIO

## Overview

This example demonstrates how to upload an app to RAM of an Espressif MCU (target) with SDIO download support from another MCU (host) using the `esp_serial_flasher`. In this case, another Espressif MCU is used as the host. Binaries to be uploaded to RAM from the host MCU to the target Espressif SoC can be found in `binaries/RAM_APP` folder and are converted into C-array during build process.

The following steps are performed in order to re-program the targets memory:

1. SDIO interface in slot 1 through which the binary will be transfered is initialized.
2. The host puts the slave device into joint download mode and tries to connect by calling `esp_loader_connect()`.
3. Then `esp_loader_mem_start()` is called for each segment in RAM.
4. `esp_loader_mem_write()` function is called repeatedly for every segment until the whole binary image is transfered.
5. `esp_loader_mem_finish()` is called with the binary entrypoint, telling the chip to start the uploaded program.
6. UART2 is initialized for the connection to the target.
7. Target output is continually read and printed out.

## Hardware Required

* Two development boards, one with an Espressif SoC with an SDMMC peripheral and one Espressif SoC with SDIO download support. Here is a short list of supported MCUs:
1. ESP32-C6
* One or two USB cables for power supply and programming.

> Note: Please check if your board has [possible issues](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/sd_pullup_requirements.html) regarding SDIO requirements.
## Hardware connection

Table below shows connection between two Espressif MCUs.

| Host (ESP32) | Target |
|:------------:|:-------------:|
| IO_18 | RESET |
| IO_19 | BOOT |
| IO_2 | D0 |
| IO_4 | D1 |
| IO_12 | D2 |
| IO_13 | D3 |
| IO_14 | CLK |
| IO_15 | CMD |
| IO_22 | UART0_RX |
| IO_23 | UART0_TX |

You can find the target SDIO pins for each target [here](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/sdio_slave.html).

SDIO pins CMD and DAT0-3 must be pulled up with adequate values, please take a look at the [SD Pull-up Requirements](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/sd_pullup_requirements.html) for more info.

> Note: For the ESP32 used as a reference, it is not possible to reassign SDIO pins, due to GPIO matrix limitations
## Build and flash

To run the example, type the following command:

```CMake
idf.py -p PORT flash monitor
```

(To exit the serial monitor, type ``Ctrl-]``.)

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

## Example output

Here is the example's console output:

```
Connected to target
I (701) sdio_ram_loader: Loading app to RAM ...
Start loading
Downloading 52296 bytes at 0x40800000...
Downloading 312 bytes at 0x4080d990...
Finished loading
I (741) sdio_ram_loader: ********************************************
I (741) sdio_ram_loader: *** Logs below are print from slave .... ***
I (751) sdio_ram_loader: ********************************************
Hello world!
...
```
14 changes: 14 additions & 0 deletions examples/esp32_sdio_load_ram_example/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
set(srcs main.c ../../common/example_common.c)
set(include_dirs . ../../common)

idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${include_dirs})
set(target ${COMPONENT_LIB})

# Embed binaries into the app.
# In ESP-IDF this can also be done using EMBED_FILES option of idf_component_register.
# Here an external tool is used to make file embedding similar with other ports.
include(${CMAKE_CURRENT_LIST_DIR}/../../common/bin2array.cmake)
create_resources(${CMAKE_CURRENT_LIST_DIR}/../../binaries/RAM_APP ${CMAKE_BINARY_DIR}/binaries.c)
set_property(SOURCE ${CMAKE_BINARY_DIR}/binaries.c PROPERTY GENERATED 1)
target_sources(${target} PRIVATE ${CMAKE_BINARY_DIR}/binaries.c)
97 changes: 97 additions & 0 deletions examples/esp32_sdio_load_ram_example/main/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/* Example of loading the program into RAM through SDIO
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 <sys/param.h>
#include <string.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_task_wdt.h"
#include "driver/sdmmc_host.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "esp32_sdio_port.h"
#include "esp_loader.h"
#include "example_common.h"
#include "freertos/FreeRTOS.h"

static const char *TAG = "sdio_ram_loader";

// Max line size
#define BUF_LEN 128
static uint8_t buf[BUF_LEN] = {0};

void slave_monitor(void *arg)
{
// Initialize UART
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
.source_clk = UART_SCLK_DEFAULT,
#endif
};

ESP_ERROR_CHECK(uart_param_config(UART_NUM_2, &uart_config));

ESP_ERROR_CHECK(uart_set_pin(UART_NUM_2, GPIO_NUM_22, GPIO_NUM_23,
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));

ESP_ERROR_CHECK(uart_driver_install(UART_NUM_2, BUF_LEN * 4, BUF_LEN * 4, 0, NULL, 0));

while (1) {
int rxBytes = uart_read_bytes(UART_NUM_2, buf, BUF_LEN, 100 / portTICK_PERIOD_MS);
buf[rxBytes] = '\0';
printf("%s", buf);
}
}

void app_main(void)
{
example_ram_app_binary_t bin;

// The ESP32 used for the example actually does not allow us to change the SD pins,
// so setting them in the configuration is meaningless.
// The pins used by the ESP32 are:
// sdio_clk_pin - GPIO14
// sdio_d0_pin - GPIO2
// sdio_d1_pin - GPIO4
// sdio_d2_pin - GPIO12
// sdio_d3_pin - GPIO13
// sdio_cmd_pin - GPIO15
const loader_esp32_sdio_config_t config = {
.slot = SDMMC_HOST_SLOT_1,
.max_freq_khz = SDMMC_FREQ_DEFAULT,
.reset_trigger_pin = GPIO_NUM_18,
.boot_pin = GPIO_NUM_19,
};

if (loader_port_esp32_sdio_init(&config) != ESP_LOADER_SUCCESS) {
ESP_LOGE(TAG, " SDIO initialization failed.");
abort();
}

if (connect_to_target(0) == ESP_LOADER_SUCCESS) {
get_example_ram_app_binary(esp_loader_get_target(), &bin);
ESP_LOGI(TAG, "Loading app to RAM ...");
esp_loader_error_t err = load_ram_binary(bin.ram_app.data);
if (err == ESP_LOADER_SUCCESS) {
// Forward slave's serial output
ESP_LOGI(TAG, "********************************************");
ESP_LOGI(TAG, "*** Logs below are print from slave .... ***");
ESP_LOGI(TAG, "********************************************");
xTaskCreate(slave_monitor, "slave_monitor", 2048, NULL, configMAX_PRIORITIES - 1, NULL);
} else {
ESP_LOGE(TAG, "Loading to RAM failed ...");
}
}
vTaskDelete(NULL);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import pytest
from pytest_embedded import Dut


@pytest.mark.esp32
def test_esp32_sdio_load_ram_example(dut: Dut) -> None:
dut.expect("Finished loading")
dut.expect("Hello world!")
2 changes: 2 additions & 0 deletions examples/esp32_sdio_load_ram_example/sdkconfig.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_SERIAL_FLASHER_INTERFACE_SDIO=y
3 changes: 2 additions & 1 deletion include/esp_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ esp_loader_error_t esp_loader_mem_write(const void *payload, uint32_t size);
*/
esp_loader_error_t esp_loader_mem_finish(uint32_t entrypoint);


#ifndef SERIAL_FLASHER_INTERFACE_SDIO
/**
* @brief Reads te MAC of the connected chip.
*
Expand Down Expand Up @@ -399,6 +399,7 @@ esp_loader_error_t esp_loader_read_register(uint32_t address, uint32_t *reg_valu
* mode or the stub is running on the target.
*/
esp_loader_error_t esp_loader_change_transmission_rate(uint32_t transmission_rate);
#endif /* SERIAL_FLASHER_INTERFACE_SDIO */

/**
* @brief Verify target's flash integrity by checking MD5.
Expand Down
Loading

0 comments on commit bcbc726

Please sign in to comment.