Skip to content

Commit

Permalink
Merge branch 'feat/support_reading_flash' into 'master'
Browse files Browse the repository at this point in the history
feat: Add support for reading from flash

Closes ESF-93

See merge request espressif/esp-serial-flasher!128
  • Loading branch information
DNedic committed Nov 25, 2024
2 parents 2837d52 + 400d614 commit e238977
Show file tree
Hide file tree
Showing 10 changed files with 417 additions and 4 deletions.
18 changes: 18 additions & 0 deletions examples/esp32_read_flash_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.5)

set(EXTRA_COMPONENT_DIRS ../../)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp-serial-flasher)

# 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()
79 changes: 79 additions & 0 deletions examples/esp32_read_flash_example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Read from target flash example

## Overview

This example demonstrates how to read from target flash.

The following steps are performed to demonstrate the flash reading functionality:

1. UART1 through which the the new binary will be transferred is initialized.
2. The host puts the target device into the boot mode and tries to connect by calling `esp_loader_connect()`.
3. `esp_loader_flash_start()` is called to enter the flashing mode and erase the amount of memory to be flashed.
5. `esp_loader_flash_write()` function is called repeatedly until the whole example data is transfered.
6. `esp_loader_flash_read()` is called to read back the data programmed into the target flash
7. Data is compared to verify successful reading

Note: In addition to the steps mentioned above, `esp_loader_change_transmission_rate()` is called after the connection is established in order to increase the flashing and reading speed. This does not apply for the ESP8266, as its bootloader does not support this command. However, the ESP8266 is capable of detecting the baud rate during connection phase and can be changed before calling `esp_loader_connect()`, if necessary.

## Connection configuration

In the majority of cases `ESP_LOADER_CONNECT_DEFAULT` helper macro is used in order to initialize `loader_connect_args_t` data structure passed to `esp_loader_connect()`. Helper macro sets the maximum time to wait for a response and the number of retrials. For more detailed information refer to [serial protocol](https://docs.espressif.com/projects/esptool/en/latest/esp32s3/advanced-topics/serial-protocol.html).

## Hardware Required

* Two development boards with the ESP32 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.).

* One or two USB cables for power supply and programming.

* Cables to connect host to target according to table below.

## Hardware connection

Table below shows connection between the two ESP32 devices.

| ESP32 (host) | ESP32 (target) |
|:------------:|:-------------:|
| IO26 | IO0 |
| IO25 | RESET |
| IO4 | RX0 |
| IO5 | TX0 |

Note: interconnection is the same for ESP32, ESP32-S2 and ESP8266 targets.

## 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](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/index.html) for full steps to configure and use ESP-IDF to build projects.

## Configuration

For details about available configuration options, please refer to the top level [README.md](../../README.md).
Compile definitions can be specified in the command line when running `idf.py`, for example:

```
idf.py build -DMD5_ENABLED=1
```

## Example output

Here is the example's console output:

```
...
Connected to target
Transmission rate changed.
I (703) serial_flasher: Loading example data
Erasing flash (this may take a while)...
Start programming
Progress: 100 %
Finished programming
Flash verified
I (1013) serial_flasher: Flash contents match example data
```
6 changes: 6 additions & 0 deletions examples/esp32_read_flash_example/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
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})
81 changes: 81 additions & 0 deletions examples/esp32_read_flash_example/main/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/* Flash multiple partitions 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.
*/

#include <sys/param.h>
#include <string.h>
#include "esp_err.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "esp32_port.h"
#include "esp_loader.h"
#include "example_common.h"

static const char *TAG = "serial_flasher";
static const char example_data[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Donec pretium sem et condimentum tincidunt.n "
"Quisque tristique in enim elementum aliquet. "
"Integer consequat sodales bibendum. "
"Nam enim quam, tristique id dui ut, fermentum porta felis. "
"Phasellus vulputate sem quis ligula egestas, sed ullamcorper eros tincidunt. "
"Donec imperdiet ac urna in placerat. "
"Praesent ultrices velit nulla, eu rutrum nisi maximus in."
"Donec non ligula molestie, blandit massa vel, auctor ipsum. "
"Nunc consectetur mi nulla, a ultricies odio vehicula a. "
"Praesent hendrerit tellus nunc, a interdum lectus mollis eget. "
"Nullam in felis vitae diam posuere dignissim quis non urna. "
"Quisque elementum ante at sapien condimentum, sit amet ultricies tortor feugiat. "
"Aliquam id mi at purus maximus lobortis. "
"Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. "
"Nunc consequat lorem turpis, vitae dignissim leo fringilla eget. "
"In ornare convallis finibus. "
"Morbi libero neque, pretium et mollis non, dictum eget felis. "
"Ut mattis vitae urna id vulputate. "
"Nam porttitor dolor diam, eu rutrum tortor auctor id...";
static uint8_t read_buf[sizeof(example_data)];

#define HIGHER_BAUDRATE 230400

void app_main(void)
{
const loader_esp32_config_t config = {
.baud_rate = 115200,
.uart_port = UART_NUM_1,
.uart_rx_pin = GPIO_NUM_5,
.uart_tx_pin = GPIO_NUM_4,
.reset_trigger_pin = GPIO_NUM_25,
.gpio0_trigger_pin = GPIO_NUM_26,
};

if (loader_port_esp32_init(&config) != ESP_LOADER_SUCCESS) {
ESP_LOGE(TAG, "serial initialization failed.");
return;
}

if (connect_to_target(HIGHER_BAUDRATE) == ESP_LOADER_SUCCESS) {

ESP_LOGI(TAG, "Loading example data");
flash_binary((const uint8_t *)example_data, sizeof(example_data), 0x00000000);

if (esp_loader_flash_read(read_buf, 0x00000000, sizeof(read_buf)) == ESP_LOADER_SUCCESS) {
if (!memcmp(example_data, read_buf, sizeof(read_buf))) {
ESP_LOGI(TAG, "Flash contents match example data");
} else {
ESP_LOGE(TAG, "Flash contents do not match example data");
ESP_LOG_BUFFER_HEXDUMP("Programmed data: ", example_data, sizeof(read_buf), ESP_LOG_ERROR);
ESP_LOG_BUFFER_HEXDUMP("Read data: ", read_buf, sizeof(read_buf), ESP_LOG_ERROR);
}
} else {
ESP_LOGE(TAG, "Could not read from flash!");
}


}
vTaskDelete(NULL);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import pytest
from pytest_embedded import Dut


@pytest.mark.esp32
def test_esp32_read_flash_example(dut: Dut) -> None:
dut.expect("Loading example data")
dut.expect("Start programming")
dut.expect("Finished programming", not_matching="Error")
dut.expect("Flash contents match example data")
1 change: 1 addition & 0 deletions examples/esp32_read_flash_example/sdkconfig.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CONFIG_IDF_TARGET="esp32"
22 changes: 19 additions & 3 deletions include/esp_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@ esp_loader_error_t esp_loader_connect_secure_download_mode(esp_loader_connect_ar
/**
* @brief Initiates flash operation
*
* @param offset[in] Address from which flash operation will be performed.
* @param image_size[in] Size of the whole binary to be loaded into flash.
* @param block_size[in] Size of buffer used in subsequent calls to esp_loader_flash_write.
* @param offset[in] Address from which flash operation will be performed. Must be 4 byte aligned.
* @param image_size[in] Size of the whole binary to be loaded into flash. Must be 4 byte aligned.
* @param block_size[in] Size of buffer used in subsequent calls to esp_loader_flash_write.
*
* @note image_size is size of the whole image, whereas, block_size is chunk of data sent
* to the target, each time esp_loader_flash_write function is called.
Expand Down Expand Up @@ -237,6 +237,22 @@ esp_loader_error_t esp_loader_flash_finish(bool reboot);
*/
esp_loader_error_t esp_loader_flash_detect_size(uint32_t *flash_size);

/**
* @brief Reads from the target flash.
*
* @param buf[out] Buffer to read into
* @param address[in] Flash address to read from.
* @param length[in] Read length in bytes.
*
* @note Higher read speeds can be achieved by using the flasher stub.
*
* @return
* - ESP_LOADER_SUCCESS Success
* - ESP_LOADER_ERROR_UNSUPPORTED_CHIP The target flash chip is not known
* - ESP_LOADER_ERROR_UNSUPPORTED_FUNC The target chip is running in secure download mode
*/
esp_loader_error_t esp_loader_flash_read(uint8_t *buf, uint32_t address, uint32_t length);

/**
* @brief Change baud rate of the stub running on the target
*
Expand Down
25 changes: 24 additions & 1 deletion private_include/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ extern "C" {
#endif

#ifndef ROUNDUP
#define ROUNDUP(a, b) (((int)a + (int)b - 1) / (int)b)
#define ROUNDUP(a, b) ((((unsigned)a + (unsigned)b - 1) / (unsigned)b) * (unsigned)b)
#endif

#define MAX_RESP_DATA_SIZE 64
#define READ_FLASH_ROM_DATA_SIZE 64

typedef enum __attribute__((packed))
{
Expand All @@ -62,12 +63,14 @@ typedef enum __attribute__((packed))
READ_REG = 0x0a,
SPI_SET_PARAMS = 0x0b,
SPI_ATTACH = 0x0d,
READ_FLASH_ROM = 0x0e,
CHANGE_BAUDRATE = 0x0f,
FLASH_DEFL_BEGIN = 0x10,
FLASH_DEFL_DATA = 0x11,
FLASH_DEFL_END = 0x12,
SPI_FLASH_MD5 = 0x13,
GET_SECURITY_INFO = 0x14,
READ_FLASH_STUB = 0xd2,
} command_t;

typedef enum __attribute__((packed))
Expand Down Expand Up @@ -115,6 +118,22 @@ typedef struct __attribute__((packed))
uint32_t stay_in_loader;
} flash_end_command_t;

typedef struct __attribute__((packed))
{
command_common_t common;
uint32_t address;
uint32_t size;
} flash_read_rom_cmd;

typedef struct __attribute__((packed))
{
command_common_t common;
uint32_t address;
uint32_t total_size;
uint32_t packet_data_size;
uint32_t max_inflight_packets;
} flash_read_stub_cmd;

typedef struct __attribute__((packed))
{
command_common_t common;
Expand Down Expand Up @@ -235,6 +254,10 @@ esp_loader_error_t loader_flash_data_cmd(const uint8_t *data, uint32_t size);

esp_loader_error_t loader_flash_end_cmd(bool stay_in_loader);

esp_loader_error_t loader_flash_read_rom_cmd(uint32_t address, uint8_t *data);

esp_loader_error_t loader_flash_read_stub_cmd(uint32_t address, uint32_t size, uint32_t size_per_packet);

esp_loader_error_t loader_sync_cmd(void);

esp_loader_error_t loader_spi_attach_cmd(uint32_t config);
Expand Down
Loading

0 comments on commit e238977

Please sign in to comment.