Просмотр исходного кода

Merge branch 'feature/support_stm32' into 'master'

STM32 support

See merge request espressif/esp-serial-flasher!13
Martin Válik 5 лет назад
Родитель
Сommit
154b3778b1
57 измененных файлов с 3302 добавлено и 293 удалено
  1. 18 2
      .gitlab-ci.yml
  2. 3 0
      .gitmodules
  3. 35 12
      CMakeLists.txt
  4. 53 6
      README.md
  5. 0 63
      example/README.md
  6. 0 163
      example/main/serial_flash_example_main.c
  7. BIN
      example/spiffs_image/hello-world.bin
  8. 143 0
      examples/common/example_common.c
  9. 23 0
      examples/common/example_common.h
  10. 1 1
      examples/flash_at_firmware/CMakeLists.txt
  11. 76 0
      examples/flash_at_firmware/README.md
  12. BIN
      examples/flash_at_firmware/image/Firmware.bin
  13. 2 0
      examples/flash_at_firmware/main/CMakeLists.txt
  14. 96 0
      examples/flash_at_firmware/main/flash_at_firmware.c
  15. 8 0
      examples/flash_multiple_partitions/CMakeLists.txt
  16. 75 0
      examples/flash_multiple_partitions/README.md
  17. 2 2
      examples/flash_multiple_partitions/main/CMakeLists.txt
  18. 72 0
      examples/flash_multiple_partitions/main/flash_multiple_partitions.c
  19. 0 0
      examples/flash_multiple_partitions/partitions_example.csv
  20. 0 0
      examples/flash_multiple_partitions/sdkconfig.defaults
  21. BIN
      examples/flash_multiple_partitions/spiffs_image/ESP32/bootloader.bin
  22. BIN
      examples/flash_multiple_partitions/spiffs_image/ESP32/hello-world.bin
  23. BIN
      examples/flash_multiple_partitions/spiffs_image/ESP32/partition-table.bin
  24. BIN
      examples/flash_multiple_partitions/spiffs_image/ESP32_S2/bootloader.bin
  25. BIN
      examples/flash_multiple_partitions/spiffs_image/ESP32_S2/hello-world.bin
  26. BIN
      examples/flash_multiple_partitions/spiffs_image/ESP32_S2/partition-table.bin
  27. BIN
      examples/flash_multiple_partitions/spiffs_image/ESP8266/bootloader.bin
  28. BIN
      examples/flash_multiple_partitions/spiffs_image/ESP8266/hello-world.bin
  29. BIN
      examples/flash_multiple_partitions/spiffs_image/ESP8266/partition-table.bin
  30. 56 0
      examples/stm32_example/CMakeLists.txt
  31. 50 0
      examples/stm32_example/Inc/main.h
  32. 443 0
      examples/stm32_example/Inc/stm32f4xx_hal_conf.h
  33. 42 0
      examples/stm32_example/Inc/stm32f4xx_it.h
  34. 57 0
      examples/stm32_example/README.md
  35. 183 0
      examples/stm32_example/Src/libc_compat.c
  36. 273 0
      examples/stm32_example/Src/main.c
  37. 109 0
      examples/stm32_example/Src/stm32f4xx_hal_msp.c
  38. 204 0
      examples/stm32_example/Src/stm32f4xx_it.c
  39. 727 0
      examples/stm32_example/Src/system_stm32f4xx.c
  40. BIN
      examples/stm32_example/images/bootloader.bin
  41. BIN
      examples/stm32_example/images/hello-world.bin
  42. BIN
      examples/stm32_example/images/partition-table.bin
  43. 6 0
      include/esp_loader.h
  44. 9 0
      include/loader_config.h
  45. 0 0
      port/esp32_port.c
  46. 168 0
      port/stm32_port.c
  47. 1 0
      private_include/serial_comm.h
  48. 20 2
      private_include/serial_comm_prv.h
  49. 224 8
      src/esp_loader.c
  50. 30 11
      src/serial_comm.c
  51. 20 0
      submodules/CMakeLists.txt
  52. 1 0
      submodules/stm32-cmake
  53. 8 16
      test/CMakeLists.txt
  54. 1 0
      test/loader_config_user.h
  55. 6 1
      test/serial_io_mock.cpp
  56. 1 0
      test/serial_io_mock.h
  57. 56 6
      test/test.cpp

+ 18 - 2
.gitlab-ci.yml

@@ -4,6 +4,7 @@ stages:
 
 variables:
   IDF_REPO: ${GITLAB_SSH_SERVER}/espressif/esp-idf.git
+  STM32_CUBE_F4_REPO: https://github.com/STMicroelectronics/STM32CubeF4
   SERIAL_FLASHER_REPO: ${GITLAB_SSH_SERVER}/espressif/esp-serial-flasher.git
   QEMU_PATH: /opt/qemu/bin/qemu-system-xtensa
 
@@ -11,10 +12,20 @@ variables:
   cit_add_ssh_key "${GITLAB_KEY}"
   git clone "${IDF_REPO}"
   cd esp-idf
-  tools/idf_tools.py --non-interactive install && eval "$(tools/idf_tools.py --non-interactive export)" || exit 1
+  tools/idf_tools.py --non-interactive install all && eval "$(tools/idf_tools.py --non-interactive export)" || exit 1
   git submodule update --init
   export IDF_PATH=$(pwd)
 
+.clone_and_setup_stm32: &clone_and_setup_stm32 |
+  cd $CI_PROJECT_DIR
+  git submodule update --init
+  git clone "${STM32_CUBE_F4_REPO}"
+  mkdir $CI_PROJECT_DIR/examples/stm32_example/build
+
+  wget -O gcc-arm-none-eabi.tar.bz2 'https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2020q2/gcc-arm-none-eabi-9-2020-q2-update-x86_64-linux.tar.bz2?revision=05382cca-1721-44e1-ae19-1e7c3dc96118&la=en&hash=D7C9D18FCA2DD9F894FD9F3C3DC9228498FA281A'
+  tar -xjf gcc-arm-none-eabi.tar.bz2
+  mv gcc-arm-none-eabi-* gcc-arm-none-eabi
+
 before_script:
   # Use CI Tools
   - curl -sSL ${CIT_LOADER_URL} | sh
@@ -29,9 +40,14 @@ build_with_idf:
     - internet
   script:
     - *clone_and_setup_idf
-    - cd $CI_PROJECT_DIR/example
+    - cd $CI_PROJECT_DIR/examples/flash_multiple_partitions
+    - idf.py build
+    - cd $CI_PROJECT_DIR/examples/flash_at_firmware
     - idf.py build
 
+    - *clone_and_setup_stm32
+    - cd $CI_PROJECT_DIR/examples/stm32_example/build
+    - cmake -DTOOLCHAIN_PREFIX=$CI_PROJECT_DIR/gcc-arm-none-eabi -DSTM32Cube_DIR=$CI_PROJECT_DIR/STM32CubeF4 .. && cmake --build .
 
 run_tests:
   stage: test

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "submodules/stm32-cmake"]
+	path = submodules/stm32-cmake
+	url = https://github.com/ObKo/stm32-cmake.git

+ 35 - 12
CMakeLists.txt

@@ -1,19 +1,42 @@
-set(COMPONENT_SRCS 
-    "src/esp_loader.c"
-    "src/serial_comm.c"
-    "src/md5_hash.c"
-    "port/esp32_uart.c")
+cmake_minimum_required(VERSION 3.5)
 
-set(COMPONENT_ADD_INCLUDEDIRS "include")
+if (DEFINED ESP_PLATFORM)
 
-set(COMPONENT_PRIV_INCLUDEDIRS "private_include" )
+    # Register component to esp-idf build system
+    set(COMPONENT_SRCS src/esp_loader.c src/serial_comm.c src/md5_hash.c port/esp32_port.c)
+    set(COMPONENT_ADD_INCLUDEDIRS "include")
+    set(COMPONENT_PRIV_INCLUDEDIRS "private_include" )
+    register_component()
+    component_compile_options(-Wstrict-prototypes)
+    set(target ${COMPONENT_LIB})
+
+else()
+
+    # Create traditional CMake target
+    add_library(flasher src/esp_loader.c src/serial_comm.c src/md5_hash.c)
+
+    target_include_directories(flasher PUBLIC include PRIVATE private_include)
+
+    if(PORT STREQUAL "STM32")
+        target_link_libraries(flasher PUBLIC stm_cube)
+        target_sources(flasher PRIVATE port/stm32_port.c)
+    else()
+        message(FATAL_ERROR "Selected port is not supported")
+    endif()
+
+    set(target flasher)
 
-if (NOT ESP_PLATFORM)
-    message(FATAL_ERROR  "This CMakeLists.txt file is only for use inside ESP-IDF. 
-                          It will need modifying to work standalone or in another project.")
 endif()
 
 
-register_component()
+if(TARGET_SOC STREQUAL "ESP32")
+    target_compile_definitions(${target} PUBLIC -DTARGET_ESP32)
+elseif(TARGET_SOC STREQUAL "ESP32_S2")
+    target_compile_definitions(${target} PUBLIC -DTARGET_ESP32_S2)
+elseif(TARGET_SOC STREQUAL "ESP8266")
+    target_compile_definitions(${target} PUBLIC -DTARGET_ESP8266)
+endif()
 
-component_compile_options(-Wstrict-prototypes)
+if(DEFINED MD5_ENABLED)
+    target_compile_definitions(${target} PUBLIC -DMD5_ENABLED=${MD5_ENABLED})
+endif()

+ 53 - 6
README.md

@@ -2,10 +2,9 @@
 
 ## Overview
 
-Serial flasher component provides portable library for flashing ESP32 from other host microcontroller. ESP32 is normally programmed via serial interface (UART) and port layer for given host microcontroller has to be implemented, if not available. Details can be found in section below.
+Serial flasher component provides portable library for flashing Espressif SoCs (`ESP32`, `ESP32-S2`, `ESP8266`) from other host microcontroller. Espressif SoCs are normally programmed via serial interface (UART). Port layer for given host microcontroller has to be implemented, if not available. Details can be found in section below.
 
-
-## Supporting new target
+## Supporting new host target
 
 In order to support new target, following function has to be implemented by user:
 
@@ -25,11 +24,59 @@ Following functions are part of serial_io.h header for convenience, however, use
 * loader_port_debug_print()
 
 Prototypes of all function mentioned above can be found in [serial_io.h](include/serial_io.h).
-Please refer to ports in `port` directory. Currently, only [ESP32 port](port/esp32_uart.c) is available.
+Please refer to ports in `port` directory. Currently, only ports for [ESP32 port](port/esp32_port.c) and [STM32 port](port/stm32_port.c) are available.
+
+## Configuration
+
+Apart from writing port (if not available), user has to provide few configuration options:
+* TARGET_SOC: one of Espressif SoCs can be selected as target to be flashed. Currently, following SoCs are supported:
+    * ESP32
+    * ESP32_S2
+    * ESP8266
+* MD5_ENABLED: if enabled, serial flasher will verify flash integrity after writing to memory.
+
+
+Configuration can be passed to `cmake` via command line:
+
+```
+cmake -DTARGET_SOC=ESP32 -DMD5_ENABLED=1 .. && cmake --build .
+```
+
+Note: in case, no compile definitions are povided, ESP32 is set as target and MD5 check is enabled by default. As ROM bootloader of ESP8266 does not support MD5_CHECK, `-DMD5_ENABLED=0` has to be passed to command line.
+
+### STM32 support
+
+STM32 port make use of STM32 HAL libraries, that does not come with CMake support. In order to compile the project, `stm32-cmake` (`cmake` support package) has to be pulled as submodule.
+
+```
+git clone --recursive https://github.com/espressif/esp-serial-flasher.git
+```
+
+If you have cloned this repository without the `--recursive` flag, you can initialize the  submodule using the following command:
+
+```
+git submodule update --init
+```
+
+In addition to configuration parameters mentioned above, following definitions has to be set:
+* TOOLCHAIN_PREFIX: path to arm toolchain (i.e /home/user/gcc-arm-none-eabi-9-2019-q4-major)
+* STM32Cube_DIR:    path to STM32 Cube libraries  (i.e /home/user/STM32Cube/Repository/STM32Cube_FW_F4_V1.25.0)
+* STM32_CHIP:       name of STM32 for which project should be compiled  (i.e STM32F407VG)
+* PORT:             STM32
+
+This can be achieved by passing definition to command line, such as:
 
-## Component integration
+```
+cmake -DTOOLCHAIN_PREFIX="/path_to_toolchain" -DSTM32Cube_DIR="path_to_stm32Cube" -DSTM32_CHIP="STM32F407VG" -DPORT="STM32" .. && cmake --build .
+```
+Alternatively, set those variables in top level `cmake` directory:
 
-At this point, this component can only be integrated with IDF. Improvement of existing CMakeList.txt file is to be done.   
+```
+set(TOOLCHAIN_PREFIX    path_to_toolchain)
+set(STM32Cube_DIR       path_to_stm32_HAL)
+set(STM32_CHIP          STM32F407VG)
+set(PORT                STM32)
+```
 
 ## Licence
 

+ 0 - 63
example/README.md

@@ -1,63 +0,0 @@
-# Serial flash example
-
-## Overview
-
-Example demonstrates how to flash ESP32 from another (host) MCU using esp_serial_flash component API. In this case, ESP32 is also used as host MCU. Binary to be flashed from one ESP32 to another is stored in partition named `spiffs`.
-
-This example is based on spiffsgen example located in IDF. For more information how to use SPIFFS Image Generator, refer to [spiffsgen example](https://github.com/espressif/esp-idf/tree/master/examples/storage/spiffsgen)
-
-Following steps are performed in order to re-program target's memory:
-
-1. UART1 through which new binary will be transfered is initialized.
-2. Filesystem is initialized and mounted.
-3. Binary file is opened and its size is acquired, as it has to be known before flashing.
-4. Host puts slave device into boot mode tries to connect by calling `loader_connect()`.
-5. Then `loader_flash_start()` is called to enter flashing mode.
-6. `loader_flash_write()` function is called repeatedly until the whole binary image is transfered.
-
-## Hardware Required
-
-* Two development boards with ESP32 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.).
-* A USB cable for power supply and programming.
-
-## Hardware connection
-
-Table below shows connection between two ESP32 devices.
-
-| ESP32 (host) | ESP32 (slave) |
-|:------------:|:-------------:|
-|    IO26      |      IO0      |
-|    IO25      |     RESET     |
-|    IO4       |      RX0      |
-|    IO5       |      TX0      |
-
-
-### 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:
-
-```
-...
-I (342) example: Initializing SPIFFS
-I (482) example: Image size: 144672
-I (902) example: Connected to target
-I (1732) example: Start programming
-I (1832) example: packet: 0  written: 1024 B
-I (1932) example: packet: 1  written: 1024 B
-...
-I (16052) example: packet: 140  written: 1024 B
-I (16152) example: packet: 141  written: 288 B
-I (16152) example: Finished programming
-```

+ 0 - 163
example/main/serial_flash_example_main.c

@@ -1,163 +0,0 @@
-/* Serial flasher 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 <string.h>
-#include "esp_err.h"
-#include "esp_log.h"
-#include "esp_spiffs.h"
-#include "esp_loader.h"
-#include "serial_io.h"
-#include "driver/gpio.h"
-#include "driver/uart.h"
-#include <sys/param.h>
-
-
-static const char *TAG = "example";
-
-const uint32_t HIGHER_BAUD_RATE = 921600;
-const uint32_t APP_START_ADDRESS = 0x10000;
-static uint8_t payload[1024];
-
-
-static void flash_binary(FILE *image, size_t image_size)
-{
-    esp_loader_error_t err;
-    int32_t packet_number = 0;
-    esp_loader_connect_args_t connect_config = ESP_LOADER_CONNECT_DEFAULT();
-
-    err = esp_loader_connect(&connect_config);
-    if (err != ESP_LOADER_SUCCESS) {
-        ESP_LOGE(TAG, "Cannot connect to target.");
-        return;
-    }
-    ESP_LOGI(TAG, "Connected to target");
-
-    err = esp_loader_change_baudrate(HIGHER_BAUD_RATE);
-    if (err != ESP_LOADER_SUCCESS) {
-        ESP_LOGE(TAG, "Unable to change baud rate on target.");
-        return;
-    }
-
-    err = loader_port_change_baudrate(HIGHER_BAUD_RATE);
-    if (err != ESP_LOADER_SUCCESS) {
-        ESP_LOGE(TAG, "Unable to change baud rate.");
-        return;
-    }
-
-    err = esp_loader_flash_start(APP_START_ADDRESS, image_size, sizeof(payload));
-    if (err != ESP_LOADER_SUCCESS) {
-        ESP_LOGE(TAG, "Flash start operation failed.");
-        return;
-    }
-    ESP_LOGI(TAG, "Start programming");
-
-    while (image_size > 0) {
-        size_t to_read = MIN(image_size, sizeof(payload));
-
-        size_t read = fread(payload, 1, to_read, image);
-        if (read != to_read) {
-            ESP_LOGE(TAG, "Error occurred while reading file.");
-            return;
-        }
-
-        err = esp_loader_flash_write(payload, to_read);
-        if (err != ESP_LOADER_SUCCESS) {
-            ESP_LOGE(TAG, "Packet could not be written");
-            return;
-        }
-
-        ESP_LOGI(TAG, "packet: %d  written: %u B", packet_number++, to_read);
-
-        image_size -= to_read;
-    };
-
-    ESP_LOGI(TAG, "Finished programming");
-
-    err = esp_loader_flash_verify();
-    if (err != ESP_LOADER_SUCCESS) {
-        ESP_LOGE(TAG, "MD5 does not match. err: %d", err);
-        return;
-    }
-    ESP_LOGI(TAG, "Flash verified");
-}
-
-
-static FILE *get_image_and_its_size(size_t *image_size)
-{
-    ESP_LOGI(TAG, "Initializing SPIFFS");
-
-    esp_vfs_spiffs_conf_t conf = {
-        .base_path = "/spiffs",
-        .partition_label = NULL,
-        .max_files = 5,
-        .format_if_mount_failed = false
-    };
-
-    // Use settings defined above to initialize and mount SPIFFS filesystem.
-    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 NULL;
-    }
-
-    FILE *image = fopen("/spiffs/hello-world.bin", "r");
-    if (image == NULL) {
-        ESP_LOGE(TAG, "Failed to open file");
-        esp_vfs_spiffs_unregister(NULL);
-        return NULL;
-    }
-
-    fseek(image, 0L, SEEK_END);
-    *image_size = ftell(image);
-    rewind(image);
-
-    ESP_LOGI(TAG, "Image size: %u", *image_size);
-
-    return image;
-}
-
-
-void app_main(void)
-{
-
-    const loader_serial_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,
-    };
-
-    // Initialize UART
-    esp_loader_error_t err = loader_port_serial_init(&config);
-    if (err != ESP_LOADER_SUCCESS) {
-        ESP_LOGE(TAG, "serial initialization failed.");
-        return;
-    }
-
-    size_t image_size;
-    FILE *image = get_image_and_its_size(&image_size);
-    if (image == NULL) {
-        return;
-    }
-
-    flash_binary(image, image_size);
-
-    // All done, close file, unmount partition and disable SPIFFS
-    fclose(image);
-    esp_vfs_spiffs_unregister(NULL);
-}

BIN
example/spiffs_image/hello-world.bin


+ 143 - 0
examples/common/example_common.c

@@ -0,0 +1,143 @@
+/* Copyright 2020 Espressif Systems (Shanghai) PTE 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.
+ */
+
+#include <sys/param.h>
+#include "esp_err.h"
+#include "esp_log.h"
+#include "serial_io.h"
+#include "esp_loader.h"
+#include "driver/uart.h"
+#include "driver/gpio.h"
+#include "example_common.h"
+
+#define HIGHER_BAUD_RATE 230400
+
+void flash_binary(FILE *image, size_t image_size, size_t address)
+{
+    esp_loader_error_t err;
+    int32_t packet_number = 0;
+    static uint8_t payload[1024];
+
+    ESP_LOGI(TAG, "Erasing flash...");
+    err = esp_loader_flash_start(address, image_size, sizeof(payload));
+    if (err != ESP_LOADER_SUCCESS) {
+        ESP_LOGE(TAG, "Erasing flash failed with error %d.", err);
+        return;
+    }
+    ESP_LOGI(TAG, "Start programming");
+
+    while (image_size > 0) {
+        size_t to_read = MIN(image_size, sizeof(payload));
+
+        size_t read = fread(payload, 1, to_read, image);
+        if (read != to_read) {
+            ESP_LOGE(TAG, "Error occurred while reading file. to_read %u, read %u", to_read, read);
+            return;
+        }
+
+        err = esp_loader_flash_write(payload, to_read);
+        if (err != ESP_LOADER_SUCCESS) {
+            ESP_LOGE(TAG, "Packet could not be written");
+            return;
+        }
+
+        printf("packet: %d  written: %u B\n", packet_number++, to_read);
+
+        image_size -= to_read;
+    };
+
+    ESP_LOGI(TAG, "Finished programming");
+
+#if MD5_ENABLED
+    err = esp_loader_flash_verify();
+    if (err != ESP_LOADER_SUCCESS) {
+        ESP_LOGE(TAG, "MD5 does not match. err: %d", err);
+        return;
+    }
+    ESP_LOGI(TAG, "Flash verified");
+#endif
+}
+
+FILE *get_image_and_its_size(const char *path, size_t *image_size)
+{
+    FILE *image = fopen(path, "r");
+    if (image == NULL) {
+        ESP_LOGE(TAG, "Failed to open file %s", path);
+        return NULL;
+    }
+
+    fseek(image, 0L, SEEK_END);
+    *image_size = ftell(image);
+    rewind(image);
+
+    ESP_LOGW(TAG, "File %s opened. Size: %u bytes", path, *image_size);
+
+    return image;
+}
+
+void upload_file(const char *path, size_t address)
+{
+    size_t image_size;
+    FILE *image = get_image_and_its_size(path, &image_size);
+
+    if (image != NULL) {
+        flash_binary(image, image_size, address);
+        fclose(image);
+    }
+}
+
+esp_err_t connect_to_target()
+{
+    const loader_serial_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,
+    };
+
+    // Initialize UART
+    esp_loader_error_t err = loader_port_serial_init(&config);
+    if (err != ESP_LOADER_SUCCESS) {
+        ESP_LOGE(TAG, "serial initialization failed.");
+        return err;
+    }
+
+    esp_loader_connect_args_t connect_config = ESP_LOADER_CONNECT_DEFAULT();
+
+    err = esp_loader_connect(&connect_config);
+    if (err != ESP_LOADER_SUCCESS) {
+        ESP_LOGE(TAG, "Cannot connect to target. Error: %u", err);
+        return err;
+    }
+    ESP_LOGI(TAG, "Connected to target");
+
+#ifndef TARGET_ESP8266
+    err = esp_loader_change_baudrate(HIGHER_BAUD_RATE);
+    if (err != ESP_LOADER_SUCCESS) {
+        ESP_LOGE(TAG, "Unable to change baud rate on target.");
+        return err;
+    }
+
+    err = loader_port_change_baudrate(HIGHER_BAUD_RATE);
+    if (err != ESP_LOADER_SUCCESS) {
+        ESP_LOGE(TAG, "Unable to change baud rate.");
+        return err;
+    }
+#endif
+
+    return ESP_OK;
+}

+ 23 - 0
examples/common/example_common.h

@@ -0,0 +1,23 @@
+/* Copyright 2020 Espressif Systems (Shanghai) PTE 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.
+ */
+
+#pragma once
+
+static const char *TAG = "example";
+
+void flash_binary(FILE *image, size_t image_size, size_t address);
+FILE *get_image_and_its_size(const char *path, size_t *image_size);
+void upload_file(const char *path, size_t address);
+esp_err_t connect_to_target();

+ 1 - 1
example/CMakeLists.txt → examples/flash_at_firmware/CMakeLists.txt

@@ -2,7 +2,7 @@
 # in this exact order for cmake to work correctly
 cmake_minimum_required(VERSION 3.5)
 
-set(EXTRA_COMPONENT_DIRS ../)
+set(EXTRA_COMPONENT_DIRS ../../)
 
 include($ENV{IDF_PATH}/tools/cmake/project.cmake)
 project(esp-serial-flasher)

+ 76 - 0
examples/flash_at_firmware/README.md

@@ -0,0 +1,76 @@
+# Flash AT firmware example
+
+## Overview
+
+Example demonstrates how to flash AT command firmware from one ESP32 to another using esp_serial_flash component API. Binary to be flashed has to be stored on SD card with `fat` filesystem. AT command firmware to copy onto SD card can be found in `image` folder. When other AT command firmware is stored on SD card, file name has to be changed in example accordingly.
+
+Following steps are performed in order to re-program target's memory:
+
+1. Filesystem is initialized and mounted.
+2. UART1 through which new binary will be transfered is initialized.
+3. Host puts slave device into boot mode tries to connect by calling `esp_loader_connect()`.
+4. Binary file is opened and its size is acquired, as it has to be known before flashing.
+5. Then `esp_loader_flash_start()` is called to enter flashing mode and erase amount of memory to be flashed.
+6. `esp_loader_flash_write()` function is called repeatedly until the whole binary image is transfered.
+
+## Hardware Required
+
+* `ESP_WROVER_KIT` (with SD card connector)
+* Another board based on WROWER module.
+* One or two USB cables for power supply and programming.
+* microSD card
+
+Note: WROWER module(ESP32) to be flashed can be substituted with any other Espressif SoC as long as appropriate AT firmware version is used.
+
+## Hardware connection
+
+Table below shows connection between two ESP32 devices.
+
+| ESP32 (host) | ESP32 (slave) |
+|:------------:|:-------------:|
+|    IO26      |      IO0      |
+|    IO25      |     RESET     |
+|    IO4       |      RX0      |
+|    IO5       |      TX0      |
+
+### 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.
+
+## Configuration
+
+For details about available configuration option, please refer to top level [README.md](../../README.md). Compile definitions can be specified on command line when running `idf.py`, for example:
+
+```
+idf.py build -DTARGET_SOC=ESP32_S2 -DMD5_ENABLED=1
+```
+By default, example is compiled for ESP32 target with MD5 check disabled.
+When target is not ESP32, provide appropriate AT command firmware binary.
+
+For available AT command firmwares refer to [AT firmwares](https://www.espressif.com/en/support/download/at)
+
+## Example output
+
+Here is the example's console output:
+
+```
+...
+I (342) example: Initializing SPIFFS
+I (482) example: Image size: 144672
+I (902) example: Connected to target
+I (1732) example: Start programming
+I (1832) example: packet: 0  written: 1024 B
+I (1932) example: packet: 1  written: 1024 B
+...
+I (16052) example: packet: 140  written: 1024 B
+I (16152) example: packet: 141  written: 288 B
+I (16152) example: Finished programming
+```

BIN
examples/flash_at_firmware/image/Firmware.bin


+ 2 - 0
examples/flash_at_firmware/main/CMakeLists.txt

@@ -0,0 +1,2 @@
+idf_component_register(SRCS "flash_at_firmware.c" "../../common/example_common.c"
+                       INCLUDE_DIRS "." "../../common")

+ 96 - 0
examples/flash_at_firmware/main/flash_at_firmware.c

@@ -0,0 +1,96 @@
+/* Flash AT firmware 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 "esp_err.h"
+#include "esp_log.h"
+#include "esp_vfs_fat.h"
+#include "driver/sdspi_host.h"
+#include "driver/spi_common.h"
+#include "example_common.h"
+
+#define MOUNT_POINT "/sdcard"
+
+#define SPI_DMA_CHAN 1
+
+#define PIN_NUM_MISO 2
+#define PIN_NUM_MOSI 15
+#define PIN_NUM_CLK  14
+#define PIN_NUM_CS   13
+
+static sdmmc_card_t *card;
+static sdmmc_host_t host = SDSPI_HOST_DEFAULT();
+
+esp_err_t sdcard_init(void)
+{
+    ESP_LOGI(TAG, "Initializing SD card");
+
+    // Use settings defined above to initialize SD card and mount FAT filesystem.
+    // Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions.
+    // Please check its source code and implement error recovery when developing
+    // production applications.
+
+    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,
+    };
+    
+    if( spi_bus_initialize(host.slot, &bus_cfg, SPI_DMA_CHAN) != ESP_OK ) {
+        ESP_LOGE(TAG, "Failed to initialize bus.");
+        return ESP_FAIL;
+    }
+
+    // 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;
+
+    esp_vfs_fat_sdmmc_mount_config_t mount_config = {
+        .format_if_mount_failed = false,
+        .max_files = 5,
+        .allocation_unit_size = 16 * 1024
+    };
+
+    const char mount_point[] = MOUNT_POINT;
+
+    esp_err_t ret = esp_vfs_fat_sdspi_mount(mount_point, &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 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 ESP_FAIL;
+    }
+
+    return ESP_OK;
+}
+
+void sdcard_deinit()
+{
+    esp_vfs_fat_sdcard_unmount(MOUNT_POINT, card);
+    ESP_LOGI(TAG, "Card unmounted");
+    spi_bus_free(host.slot);
+}
+
+void app_main(void)
+{
+    if ( sdcard_init() == ESP_OK ) {
+        if ( connect_to_target() == ESP_OK) {
+            upload_file(MOUNT_POINT"/Firmware.bin", 0);
+        }
+        sdcard_deinit();
+    }
+}

+ 8 - 0
examples/flash_multiple_partitions/CMakeLists.txt

@@ -0,0 +1,8 @@
+# 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)

+ 75 - 0
examples/flash_multiple_partitions/README.md

@@ -0,0 +1,75 @@
+# Flash multiple partitions example
+
+## Overview
+
+Example demonstrates how to flash ESP32/ESP32-S2/ESP8266 from another (host) MCU using esp_serial_flash component API. In this case, ESP32 is also used as host MCU. Binary to be flashed from host MCU to ESP* is stored in partition named `spiffs`. Binaries are placed in separate folder for each target.
+
+This example is based on spiffsgen example located in IDF. For more information how to use SPIFFS Image Generator, refer to [spiffsgen example](https://github.com/espressif/esp-idf/tree/master/examples/storage/spiffsgen)
+
+Following steps are performed in order to re-program target's memory:
+
+1. Filesystem is initialized and mounted.
+2. UART1 through which new binary will be transfered is initialized.
+3. Host puts slave device into boot mode tries to connect by calling `esp_loader_connect()`.
+4. Binary file is opened and its size is acquired, as it has to be known before flashing.
+5. Then `esp_loader_flash_start()` is called to enter flashing mode and erase amount of memory to be flashed.
+6. `esp_loader_flash_write()` function is called repeatedly until the whole binary image is transfered.
+
+Note: In addition, to steps mentioned above, `esp_loader_change_baudrate`  is called after connection is established in order to increase flashing speed. This does not apply for ESP8266, as its bootloader does not support this command. However, ESP8266 is capable of detecting baud rate during connection phase, and can be changed before calling `esp_loader_connect`, if necessary.
+
+## Hardware Required
+
+* Two development boards with ESP32 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.).
+* One or two USB cables for power supply and programming.
+
+## Hardware connection
+
+Table below shows connection between two ESP32 devices.
+
+| ESP32 (host) | ESP32 (slave) |
+|:------------:|:-------------:|
+|    IO26      |      IO0      |
+|    IO25      |     RESET     |
+|    IO4       |      RX0      |
+|    IO5       |      TX0      |
+
+Note: interconnection is the same for all three targets (slaves). 
+
+## 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.
+
+## Configuration
+
+For details about available configuration option, please refer to top level [README.md](../../README.md). Compile definitions can be specified on command line when running `idf.py`, for example:
+
+```
+idf.py build -DTARGET_SOC=ESP32_S2 -DMD5_ENABLED=1
+```
+By default, example is compiled for ESP32 target with MD5 check disabled.
+
+## Example output
+
+Here is the example's console output:
+
+```
+...
+I (342) example: Initializing SPIFFS
+I (482) example: Image size: 144672
+I (902) example: Connected to target
+I (1732) example: Start programming
+I (1832) example: packet: 0  written: 1024 B
+I (1932) example: packet: 1  written: 1024 B
+...
+I (16052) example: packet: 140  written: 1024 B
+I (16152) example: packet: 141  written: 288 B
+I (16152) example: Finished programming
+```

+ 2 - 2
example/main/CMakeLists.txt → examples/flash_multiple_partitions/main/CMakeLists.txt

@@ -1,5 +1,5 @@
-idf_component_register(SRCS "serial_flash_example_main.c"
-                    INCLUDE_DIRS ".")
+idf_component_register(SRCS "flash_multiple_partitions.c" "../../common/example_common.c"
+                       INCLUDE_DIRS ".""../../common")
 
 # Create a SPIFFS image from the contents of the 'spiffs_image' directory
 # that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that

+ 72 - 0
examples/flash_multiple_partitions/main/flash_multiple_partitions.c

@@ -0,0 +1,72 @@
+/* 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 "esp_spiffs.h"
+#include "loader_config.h"
+#include "example_common.h"
+
+
+#ifndef TARGET_ESP8266
+const uint32_t BOOTLOADER_ADDRESS = 0x1000;
+#else
+const uint32_t BOOTLOADER_ADDRESS = 0x0;
+#endif
+const uint32_t PARTITION_ADDRESS = 0x8000;
+const uint32_t APPLICATION_ADDRESS = 0x10000;
+
+#if defined TARGET_ESP8266
+#define BINARY_PATH "/spiffs/ESP8266/"
+#elif defined TARGET_ESP32
+#define BINARY_PATH "/spiffs/ESP32/"
+#elif defined TARGET_ESP32_S2
+#define BINARY_PATH "/spiffs/ESP32_S2/"
+#endif
+
+static esp_err_t register_vfs()
+{
+    ESP_LOGI(TAG, "Initializing SPIFFS");
+
+    esp_vfs_spiffs_conf_t conf = {
+        .base_path = "/spiffs",
+        .partition_label = NULL,
+        .max_files = 5,
+        .format_if_mount_failed = false
+    };
+
+    // Use settings defined above to initialize and mount SPIFFS filesystem.
+    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;
+}
+
+void app_main(void)
+{
+    if ( register_vfs() == ESP_OK ) {
+        if ( connect_to_target() == ESP_OK) {
+            upload_file(BINARY_PATH"partition-table.bin", PARTITION_ADDRESS);
+            upload_file(BINARY_PATH"bootloader.bin", BOOTLOADER_ADDRESS);
+            upload_file(BINARY_PATH"hello-world.bin", APPLICATION_ADDRESS);
+        }
+        esp_vfs_spiffs_unregister(NULL);
+    }
+}

+ 0 - 0
example/partitions_example.csv → examples/flash_multiple_partitions/partitions_example.csv


+ 0 - 0
example/sdkconfig.defaults → examples/flash_multiple_partitions/sdkconfig.defaults


BIN
examples/flash_multiple_partitions/spiffs_image/ESP32/bootloader.bin


BIN
examples/flash_multiple_partitions/spiffs_image/ESP32/hello-world.bin


BIN
examples/flash_multiple_partitions/spiffs_image/ESP32/partition-table.bin


BIN
examples/flash_multiple_partitions/spiffs_image/ESP32_S2/bootloader.bin


BIN
examples/flash_multiple_partitions/spiffs_image/ESP32_S2/hello-world.bin


BIN
examples/flash_multiple_partitions/spiffs_image/ESP32_S2/partition-table.bin


BIN
examples/flash_multiple_partitions/spiffs_image/ESP8266/bootloader.bin


BIN
examples/flash_multiple_partitions/spiffs_image/ESP8266/hello-world.bin


BIN
examples/flash_multiple_partitions/spiffs_image/ESP8266/partition-table.bin


+ 56 - 0
examples/stm32_example/CMakeLists.txt

@@ -0,0 +1,56 @@
+cmake_minimum_required(VERSION 3.5)
+
+# Creates C resources file from files in given directory
+function(create_resources dir output)
+    # Create empty output file
+    file(WRITE ${output} "")
+    # Collect input files
+    file(GLOB bins ${dir}/*)
+    # Iterate through input files
+    foreach(bin ${bins})
+        # Get short filenames
+        string(REGEX MATCH "([^/]+)$" filename ${bin})
+        message(STATUS "filename: " ${filename})
+        # Replace filename spaces & extension separator for C compatibility
+        string(REGEX REPLACE "\\.| |-" "_" filename ${filename})
+        # Read hex data from file
+        file(READ ${bin} filedata HEX)
+        # Convert hex data for C compatibility
+        string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," filedata ${filedata})
+        # Append data to output file
+        file(APPEND ${output} "const unsigned char ${filename}[] = {${filedata}};\nconst unsigned ${filename}_size = sizeof(${filename});\n")
+    endforeach()
+endfunction()
+
+set(TOOLCHAIN_PREFIX / CACHE PATH "Path to arm toolchain")
+set(STM32Cube_DIR / CACHE PATH "Path to STM32 hal library")
+
+set(FLASHER_DIR          ${CMAKE_CURRENT_LIST_DIR}/../..)
+set(CMAKE_TOOLCHAIN_FILE ${FLASHER_DIR}/submodules/stm32-cmake/cmake/gcc_stm32.cmake)
+set(STM32_CHIP           STM32F407VG)
+set(PORT                 STM32)
+
+project(stm32_flasher)
+    
+enable_language(ASM)
+
+create_resources(images Src/binaries.c)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} Inc)
+ 
+add_executable(${CMAKE_PROJECT_NAME} 
+    Src/main.c
+    Src/stm32f4xx_hal_msp.c
+    Src/stm32f4xx_it.c
+    Src/libc_compat.c
+    Src/binaries.c)
+
+add_subdirectory(${FLASHER_DIR}/submodules ${CMAKE_BINARY_DIR}/submodules)
+add_subdirectory(${FLASHER_DIR} ${CMAKE_BINARY_DIR}/flasher)
+
+target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE stm_cube flasher)
+ 
+STM32_ADD_HEX_BIN_TARGETS(${CMAKE_PROJECT_NAME})
+
+add_custom_target(BuildBinary ALL)
+add_dependencies(BuildBinary ${CMAKE_PROJECT_NAME}.bin)

+ 50 - 0
examples/stm32_example/Inc/main.h

@@ -0,0 +1,50 @@
+/**
+  ******************************************************************************
+  * @file           : main.h
+  * @brief          : Header for main.c file.
+  *                   This file contains the common defines of the application.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under BSD 3-Clause license,
+  * the "License"; You may not use this file except in compliance with the
+  * License. You may obtain a copy of the License at:
+  *                        opensource.org/licenses/BSD-3-Clause
+  *
+  ******************************************************************************
+  */
+
+#ifndef __MAIN_H
+#define __MAIN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stm32f4xx_hal.h"
+
+void Error_Handler(void);
+
+#define GREEN_LED_Pin GPIO_PIN_12
+#define GREEN_LED_GPIO_Port GPIOD
+#define ORANGE_LED_Pin GPIO_PIN_13
+#define ORANGE_LED_GPIO_Port GPIOD
+#define RED_LED_Pin GPIO_PIN_14
+#define RED_LED_GPIO_Port GPIOD
+#define BLUE_LED_Pin GPIO_PIN_15
+#define BLUE_LED_GPIO_Port GPIOD
+#define TARGET_RST_Pin GPIO_PIN_4
+#define TARGET_RST_GPIO_Port GPIOB
+#define TARGET_IO0_Pin GPIO_PIN_5
+#define TARGET_IO0_GPIO_Port GPIOB
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MAIN_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 443 - 0
examples/stm32_example/Inc/stm32f4xx_hal_conf.h

@@ -0,0 +1,443 @@
+/**
+  ******************************************************************************
+  * @file    stm32f4xx_hal_conf_template.h
+  * @author  MCD Application Team
+  * @brief   HAL configuration template file. 
+  *          This file should be copied to the application folder and renamed
+  *          to stm32f4xx_hal_conf.h.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under BSD 3-Clause license,
+  * the "License"; You may not use this file except in compliance with the
+  * License. You may obtain a copy of the License at:
+  *                        opensource.org/licenses/BSD-3-Clause
+  *
+  ******************************************************************************
+  */ 
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_H
+#define __STM32F4xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* ########################## Module Selection ############################## */
+/**
+  * @brief This is the list of modules to be used in the HAL driver 
+  */
+#define HAL_MODULE_ENABLED  
+
+  /* #define HAL_ADC_MODULE_ENABLED   */
+/* #define HAL_CRYP_MODULE_ENABLED   */
+/* #define HAL_CAN_MODULE_ENABLED   */
+/* #define HAL_CRC_MODULE_ENABLED   */
+/* #define HAL_CRYP_MODULE_ENABLED   */
+/* #define HAL_DAC_MODULE_ENABLED   */
+/* #define HAL_DCMI_MODULE_ENABLED   */
+/* #define HAL_DMA2D_MODULE_ENABLED   */
+/* #define HAL_ETH_MODULE_ENABLED   */
+/* #define HAL_NAND_MODULE_ENABLED   */
+/* #define HAL_NOR_MODULE_ENABLED   */
+/* #define HAL_PCCARD_MODULE_ENABLED   */
+/* #define HAL_SRAM_MODULE_ENABLED   */
+/* #define HAL_SDRAM_MODULE_ENABLED   */
+/* #define HAL_HASH_MODULE_ENABLED   */
+/* #define HAL_I2C_MODULE_ENABLED   */
+/* #define HAL_I2S_MODULE_ENABLED   */
+/* #define HAL_IWDG_MODULE_ENABLED   */
+/* #define HAL_LTDC_MODULE_ENABLED   */
+/* #define HAL_RNG_MODULE_ENABLED   */
+/* #define HAL_RTC_MODULE_ENABLED   */
+/* #define HAL_SAI_MODULE_ENABLED   */
+/* #define HAL_SD_MODULE_ENABLED   */
+/* #define HAL_MMC_MODULE_ENABLED   */
+/* #define HAL_SPI_MODULE_ENABLED   */
+/* #define HAL_TIM_MODULE_ENABLED   */
+#define HAL_UART_MODULE_ENABLED
+/* #define HAL_USART_MODULE_ENABLED   */
+/* #define HAL_IRDA_MODULE_ENABLED   */
+/* #define HAL_SMARTCARD_MODULE_ENABLED   */
+/* #define HAL_SMBUS_MODULE_ENABLED   */
+/* #define HAL_WWDG_MODULE_ENABLED   */
+/* #define HAL_PCD_MODULE_ENABLED   */
+/* #define HAL_HCD_MODULE_ENABLED   */
+/* #define HAL_DSI_MODULE_ENABLED   */
+/* #define HAL_QSPI_MODULE_ENABLED   */
+/* #define HAL_QSPI_MODULE_ENABLED   */
+/* #define HAL_CEC_MODULE_ENABLED   */
+/* #define HAL_FMPI2C_MODULE_ENABLED   */
+/* #define HAL_SPDIFRX_MODULE_ENABLED   */
+/* #define HAL_DFSDM_MODULE_ENABLED   */
+/* #define HAL_LPTIM_MODULE_ENABLED   */
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_EXTI_MODULE_ENABLED
+#define HAL_DMA_MODULE_ENABLED
+#define HAL_RCC_MODULE_ENABLED
+#define HAL_FLASH_MODULE_ENABLED
+#define HAL_PWR_MODULE_ENABLED
+#define HAL_CORTEX_MODULE_ENABLED
+
+/* ########################## HSE/HSI Values adaptation ##################### */
+/**
+  * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
+  *        This value is used by the RCC HAL module to compute the system frequency
+  *        (when HSE is used as system clock source, directly or through the PLL).  
+  */
+#if !defined  (HSE_VALUE) 
+  #define HSE_VALUE    ((uint32_t)25000000U) /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined  (HSE_STARTUP_TIMEOUT)
+  #define HSE_STARTUP_TIMEOUT    ((uint32_t)100U)   /*!< Time out for HSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+  * @brief Internal High Speed oscillator (HSI) value.
+  *        This value is used by the RCC HAL module to compute the system frequency
+  *        (when HSI is used as system clock source, directly or through the PLL). 
+  */
+#if !defined  (HSI_VALUE)
+  #define HSI_VALUE    ((uint32_t)16000000U) /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI_VALUE */
+
+/**
+  * @brief Internal Low Speed oscillator (LSI) value.
+  */
+#if !defined  (LSI_VALUE) 
+ #define LSI_VALUE  ((uint32_t)32000U)       /*!< LSI Typical Value in Hz*/
+#endif /* LSI_VALUE */                      /*!< Value of the Internal Low Speed oscillator in Hz
+                                             The real value may vary depending on the variations
+                                             in voltage and temperature.*/
+/**
+  * @brief External Low Speed oscillator (LSE) value.
+  */
+#if !defined  (LSE_VALUE)
+ #define LSE_VALUE  ((uint32_t)32768U)    /*!< Value of the External Low Speed oscillator in Hz */
+#endif /* LSE_VALUE */
+
+#if !defined  (LSE_STARTUP_TIMEOUT)
+  #define LSE_STARTUP_TIMEOUT    ((uint32_t)5000U)   /*!< Time out for LSE start up, in ms */
+#endif /* LSE_STARTUP_TIMEOUT */
+
+/**
+  * @brief External clock source for I2S peripheral
+  *        This value is used by the I2S HAL module to compute the I2S clock source 
+  *        frequency, this source is inserted directly through I2S_CKIN pad. 
+  */
+#if !defined  (EXTERNAL_CLOCK_VALUE)
+  #define EXTERNAL_CLOCK_VALUE    ((uint32_t)12288000U) /*!< Value of the External audio frequency in Hz*/
+#endif /* EXTERNAL_CLOCK_VALUE */
+
+/* Tip: To avoid modifying this file each time you need to use different HSE,
+   ===  you can define the HSE value in your toolchain compiler preprocessor. */
+
+/* ########################### System Configuration ######################### */
+/**
+  * @brief This is the HAL system configuration section
+  */
+#define  VDD_VALUE		      ((uint32_t)3300U) /*!< Value of VDD in mv */           
+#define  TICK_INT_PRIORITY            ((uint32_t)0U)   /*!< tick interrupt priority */            
+#define  USE_RTOS                     0U     
+#define  PREFETCH_ENABLE              1U
+#define  INSTRUCTION_CACHE_ENABLE     1U
+#define  DATA_CACHE_ENABLE            1U
+
+/* ########################## Assert Selection ############################## */
+/**
+  * @brief Uncomment the line below to expanse the "assert_param" macro in the 
+  *        HAL drivers code
+  */
+/* #define USE_FULL_ASSERT    1U */
+
+/* ################## Ethernet peripheral configuration ##################### */
+
+/* Section 1 : Ethernet peripheral configuration */
+
+/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */
+#define MAC_ADDR0   2U
+#define MAC_ADDR1   0U
+#define MAC_ADDR2   0U
+#define MAC_ADDR3   0U
+#define MAC_ADDR4   0U
+#define MAC_ADDR5   0U
+
+/* Definition of the Ethernet driver buffers size and count */   
+#define ETH_RX_BUF_SIZE                ETH_MAX_PACKET_SIZE /* buffer size for receive               */
+#define ETH_TX_BUF_SIZE                ETH_MAX_PACKET_SIZE /* buffer size for transmit              */
+#define ETH_RXBUFNB                    ((uint32_t)4U)       /* 4 Rx buffers of size ETH_RX_BUF_SIZE  */
+#define ETH_TXBUFNB                    ((uint32_t)4U)       /* 4 Tx buffers of size ETH_TX_BUF_SIZE  */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848_PHY_ADDRESS Address*/ 
+#define DP83848_PHY_ADDRESS           0x01U
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ 
+#define PHY_RESET_DELAY                 ((uint32_t)0x000000FFU)
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY                ((uint32_t)0x00000FFFU)
+
+#define PHY_READ_TO                     ((uint32_t)0x0000FFFFU)
+#define PHY_WRITE_TO                    ((uint32_t)0x0000FFFFU)
+
+/* Section 3: Common PHY Registers */
+
+#define PHY_BCR                         ((uint16_t)0x0000U)    /*!< Transceiver Basic Control Register   */
+#define PHY_BSR                         ((uint16_t)0x0001U)    /*!< Transceiver Basic Status Register    */
+ 
+#define PHY_RESET                       ((uint16_t)0x8000U)  /*!< PHY Reset */
+#define PHY_LOOPBACK                    ((uint16_t)0x4000U)  /*!< Select loop-back mode */
+#define PHY_FULLDUPLEX_100M             ((uint16_t)0x2100U)  /*!< Set the full-duplex mode at 100 Mb/s */
+#define PHY_HALFDUPLEX_100M             ((uint16_t)0x2000U)  /*!< Set the half-duplex mode at 100 Mb/s */
+#define PHY_FULLDUPLEX_10M              ((uint16_t)0x0100U)  /*!< Set the full-duplex mode at 10 Mb/s  */
+#define PHY_HALFDUPLEX_10M              ((uint16_t)0x0000U)  /*!< Set the half-duplex mode at 10 Mb/s  */
+#define PHY_AUTONEGOTIATION             ((uint16_t)0x1000U)  /*!< Enable auto-negotiation function     */
+#define PHY_RESTART_AUTONEGOTIATION     ((uint16_t)0x0200U)  /*!< Restart auto-negotiation function    */
+#define PHY_POWERDOWN                   ((uint16_t)0x0800U)  /*!< Select the power down mode           */
+#define PHY_ISOLATE                     ((uint16_t)0x0400U)  /*!< Isolate PHY from MII                 */
+
+#define PHY_AUTONEGO_COMPLETE           ((uint16_t)0x0020U)  /*!< Auto-Negotiation process completed   */
+#define PHY_LINKED_STATUS               ((uint16_t)0x0004U)  /*!< Valid link established               */
+#define PHY_JABBER_DETECTION            ((uint16_t)0x0002U)  /*!< Jabber condition detected            */
+  
+/* Section 4: Extended PHY Registers */
+#define PHY_SR                          ((uint16_t)0x10U)    /*!< PHY status register Offset                      */
+
+#define PHY_SPEED_STATUS                ((uint16_t)0x0002U)  /*!< PHY Speed mask                                  */
+#define PHY_DUPLEX_STATUS               ((uint16_t)0x0004U)  /*!< PHY Duplex mask                                 */
+
+/* ################## SPI peripheral configuration ########################## */
+
+/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
+* Activated: CRC code is present inside driver
+* Deactivated: CRC code cleaned from driver
+*/
+
+#define USE_SPI_CRC                     0U
+
+/* Includes ------------------------------------------------------------------*/
+/**
+  * @brief Include module's header file 
+  */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+  #include "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_EXTI_MODULE_ENABLED
+  #include "stm32f4xx_hal_exti.h"
+#endif /* HAL_EXTI_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+  #include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+  #include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+   
+#ifdef HAL_CORTEX_MODULE_ENABLED
+  #include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+  #include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+  #include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+  #include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+  #include "stm32f4xx_hal_cryp.h" 
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_SMBUS_MODULE_ENABLED
+#include "stm32f4xx_hal_smbus.h"
+#endif /* HAL_SMBUS_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+  #include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+  #include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+  #include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+  #include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+  #include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+ 
+#ifdef HAL_SRAM_MODULE_ENABLED
+  #include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+  #include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+  #include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+  #include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */ 
+  
+#ifdef HAL_SDRAM_MODULE_ENABLED
+  #include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */      
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_MMC_MODULE_ENABLED
+ #include "stm32f4xx_hal_mmc.h"
+#endif /* HAL_MMC_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32f4xx_hal_hcd.h"
+#endif /* HAL_HCD_MODULE_ENABLED */
+   
+#ifdef HAL_DSI_MODULE_ENABLED
+ #include "stm32f4xx_hal_dsi.h"
+#endif /* HAL_DSI_MODULE_ENABLED */
+
+#ifdef HAL_QSPI_MODULE_ENABLED
+ #include "stm32f4xx_hal_qspi.h"
+#endif /* HAL_QSPI_MODULE_ENABLED */
+
+#ifdef HAL_CEC_MODULE_ENABLED
+ #include "stm32f4xx_hal_cec.h"
+#endif /* HAL_CEC_MODULE_ENABLED */
+
+#ifdef HAL_FMPI2C_MODULE_ENABLED
+ #include "stm32f4xx_hal_fmpi2c.h"
+#endif /* HAL_FMPI2C_MODULE_ENABLED */
+
+#ifdef HAL_SPDIFRX_MODULE_ENABLED
+ #include "stm32f4xx_hal_spdifrx.h"
+#endif /* HAL_SPDIFRX_MODULE_ENABLED */
+
+#ifdef HAL_DFSDM_MODULE_ENABLED
+ #include "stm32f4xx_hal_dfsdm.h"
+#endif /* HAL_DFSDM_MODULE_ENABLED */
+
+#ifdef HAL_LPTIM_MODULE_ENABLED
+ #include "stm32f4xx_hal_lptim.h"
+#endif /* HAL_LPTIM_MODULE_ENABLED */
+   
+/* Exported macro ------------------------------------------------------------*/
+#ifdef  USE_FULL_ASSERT
+/**
+  * @brief  The assert_param macro is used for function's parameters check.
+  * @param  expr: If expr is false, it calls assert_failed function
+  *         which reports the name of the source file and the source
+  *         line number of the call that failed. 
+  *         If expr is true, it returns no value.
+  * @retval None
+  */
+  #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+  void assert_failed(uint8_t* file, uint32_t line);
+#else
+  #define assert_param(expr) ((void)0U)
+#endif /* USE_FULL_ASSERT */    
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32F4xx_HAL_CONF_H */
+ 
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 42 - 0
examples/stm32_example/Inc/stm32f4xx_it.h

@@ -0,0 +1,42 @@
+/**
+  ******************************************************************************
+  * @file    stm32f4xx_it.h
+  * @brief   This file contains the headers of the interrupt handlers.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under BSD 3-Clause license,
+  * the "License"; You may not use this file except in compliance with the
+  * License. You may obtain a copy of the License at:
+  *                        opensource.org/licenses/BSD-3-Clause
+  *
+ ******************************************************************************
+  */
+
+#ifndef __STM32F4xx_IT_H
+#define __STM32F4xx_IT_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif 
+
+void NMI_Handler(void);
+void HardFault_Handler(void);
+void MemManage_Handler(void);
+void BusFault_Handler(void);
+void UsageFault_Handler(void);
+void SVC_Handler(void);
+void DebugMon_Handler(void);
+void PendSV_Handler(void);
+void SysTick_Handler(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32F4xx_IT_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 57 - 0
examples/stm32_example/README.md

@@ -0,0 +1,57 @@
+# Flash multiple partitions example
+
+## Overview
+
+Example demonstrates how to flash ESP32 from another STM32 (host MCU) using esp_serial_flash component API. STM32F4-Discovery board is used in this example, as STM32F407VG has FLASH memory large enough to fit the whole hello-world example of ESP32. Binaries to be flashed from host MCU to ESP32 can be found in images directory and converted into C-arrays during build process. USART1 is dedicated for communication with ESP32, whereas, USART2 can be used for debug purposes by attaching UART-to-USB bridge.
+
+Following steps are performed in order to re-program target's memory:
+
+1. Peripherals are initialized.
+2. Host puts slave device into boot mode tries to connect by calling `esp_loader_connect()`.
+3. Then `esp_loader_flash_start()` is called to enter flashing mode and erase amount of memory to be flashed.
+4. `esp_loader_flash_write()` function is called repeatedly until the whole binary image is transfered.
+
+Note: In addition, to steps mentioned above, `esp_loader_change_baudrate`  is called after connection is established in order to increase flashing speed. Bootloader is also capable of detecting baud rate during connection phase, and can be changed before calling `esp_loader_connect`. However, it is recommended to start at lower speed and then use dedicated command to increase baud rate. This does not apply for ESP8266, as its bootloader does not support this command, therefore, baud rate can only be changed before connection phase in this case.
+
+## Hardware Required
+
+* STM32F4-Discovery board. 
+* A development board with ESP32 SoC (e.g. ESP-WROVER-KIT, ESP32-DevKitC, etc.).
+* One or two USB cables for power supply and programming.
+
+## Hardware connection
+
+Table below shows connection between STM32 and ESP32.
+
+| STM32 (host) | ESP32 (slave) |
+|:------------:|:-------------:|
+|    PB5       |      IO0      |
+|    PB4       |      RST      |
+|    PB6       |      RX0      |
+|    PB7       |      TX0      |
+
+Optionally, UART-to-USB bridge can be connected to PD5(RX) and PD6(TX) for debug purposes.
+
+## Build and flash
+
+To compile the example:
+
+Create and navigate to `build` directory:
+```
+mkdir build && cd build
+```
+Run cmake (with appropriate parameters) and build: 
+```
+cmake -DTOOLCHAIN_PREFIX="/path_to_toolchain" -DSTM32Cube_DIR="path_to_stm32Cube" -DSTM32_CHIP="STM32F407VG" -DPORT="STM32" .. && cmake --build .
+```
+
+For more details regarding to esp_serial_flasher configuration and STM32 support, please refer to top level [README.md](../../README.md).
+
+Note: CMake 3.13 or later is required.
+
+## STM32CubeMx configuration
+
+Following configuration was used to generate STM32 `cmake` based project:
+* Project tab: Toolchain/IDE - Other toolchain (GPDSC)
+* Code Generator tab: Add necessary files as reference in the toolchain project configuration file
+

+ 183 - 0
examples/stm32_example/Src/libc_compat.c

@@ -0,0 +1,183 @@
+/* libc_compat
+
+   This 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 <errno.h>
+#include <sys/stat.h>
+#include <sys/times.h>
+#include <sys/unistd.h>
+#include <sys/time.h>
+
+#if defined STM32F1
+# include <stm32f1xx_hal.h>
+#elif defined STM32F2
+# include <stm32f2xx_hal.h>
+#elif defined STM32F4
+# include <stm32f4xx_hal.h>
+#elif defined STM32G0
+# include <stm32g0xx_hal.h>
+#endif
+
+extern uint32_t __get_MSP(void);
+extern UART_HandleTypeDef huart2;
+extern uint64_t virtualTimer;
+
+#undef errno
+extern int errno;
+
+char *__env[1] = { 0 };
+char **environ = __env;
+
+int _write(int file, char *ptr, int len);
+
+void _exit(int status)
+{
+    while (1);
+}
+
+int _close(int file)
+{
+    return -1;
+}
+
+int _execve(char *name, char **argv, char **env)
+{
+    errno = ENOMEM;
+    return -1;
+}
+
+int _fork()
+{
+    errno = EAGAIN;
+    return -1;
+}
+
+int _fstat(int file, struct stat *st)
+{
+    st->st_mode = S_IFCHR;
+    return 0;
+}
+
+int _getpid()
+{
+    return 1;
+}
+
+int _gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+    tv->tv_sec = HAL_GetTick() / 1000;
+    tv->tv_usec = (HAL_GetTick() % 1000) * 1000;
+    return 0;
+}
+
+int _isatty(int file)
+{
+    switch (file)
+    {
+    case STDOUT_FILENO:
+    case STDERR_FILENO:
+    case STDIN_FILENO:
+        return 1;
+    default:
+        //errno = ENOTTY;
+        errno = EBADF;
+        return 0;
+    }
+}
+
+int _kill(int pid, int sig)
+{
+    errno = EINVAL;
+    return (-1);
+}
+
+int _link(char *old, char *new)
+{
+    errno = EMLINK;
+    return -1;
+}
+
+int _lseek(int file, int ptr, int dir)
+{
+    return 0;
+}
+
+caddr_t _sbrk(int incr)
+{
+    extern char _ebss;
+    static char *heap_end= &_ebss;
+    char *prev_heap_end;
+
+    prev_heap_end = heap_end;
+
+    char * stack = (char*) __get_MSP();
+    if (heap_end + incr > stack)
+    {
+        _write(STDERR_FILENO, "Heap and stack collision\n", 25);
+        errno = ENOMEM;
+        return (caddr_t) - 1;
+        //abort ();
+    }
+
+    heap_end += incr;
+    return (caddr_t) prev_heap_end;
+
+}
+
+int _read(int file, char *ptr, int len)
+{
+    switch (file)
+    {
+    case STDIN_FILENO:
+        HAL_UART_Receive(&huart2, (uint8_t *)ptr, 1, HAL_MAX_DELAY);
+        return 1;
+    default:
+        errno = EBADF;
+        return -1;
+    }
+}
+
+int _stat(const char *filepath, struct stat *st)
+{
+    st->st_mode = S_IFCHR;
+    return 0;
+}
+
+clock_t _times(struct tms *buf)
+{
+    return -1;
+}
+
+int _unlink(char *name)
+{
+    errno = ENOENT;
+    return -1;
+}
+
+int _wait(int *status)
+{
+    errno = ECHILD;
+    return -1;
+}
+
+int _write(int file, char *ptr, int len)
+{
+    switch (file)
+    {
+    case STDOUT_FILENO: /*stdout*/
+        HAL_UART_Transmit(&huart2, (uint8_t*)ptr, len, HAL_MAX_DELAY);
+        break;
+    case STDERR_FILENO: /* stderr */
+        HAL_UART_Transmit(&huart2, (uint8_t*)ptr, len, HAL_MAX_DELAY);
+        break;
+    default:
+        errno = EBADF;
+        return -1;
+    }
+    return len;
+}

+ 273 - 0
examples/stm32_example/Src/main.c

@@ -0,0 +1,273 @@
+/**
+  ******************************************************************************
+  * @file           : main.c
+  * @brief          : Main program body
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under BSD 3-Clause license,
+  * the "License"; You may not use this file except in compliance with the
+  * License. You may obtain a copy of the License at:
+  *                        opensource.org/licenses/BSD-3-Clause
+  *
+  ******************************************************************************
+  */
+
+#include "main.h"
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/param.h>
+#include "serial_io.h"
+#include "esp_loader.h"
+
+UART_HandleTypeDef huart1;
+UART_HandleTypeDef huart2;
+
+void SystemClock_Config(void);
+static void MX_GPIO_Init(void);
+static void MX_USART1_UART_Init(void);
+static void MX_USART2_UART_Init(void);
+
+void flash_images(void);
+void loader_port_stm32_init(UART_HandleTypeDef *huart, 
+                            GPIO_TypeDef* port_io0, 
+                            uint16_t pin_num_io0, 
+                            GPIO_TypeDef* port_rst, 
+                            uint16_t pin_num_rst);
+
+extern const unsigned char bootloader_bin[];
+extern const unsigned bootloader_bin_size;
+extern const unsigned char hello_world_bin[];
+extern const unsigned hello_world_bin_size;
+extern const unsigned char partition_table_bin[];
+extern const unsigned partition_table_bin_size;
+
+const uint32_t BOOTLOADER_ADDRESS  = 0x1000;
+const uint32_t PARTITION_ADDRESS   = 0x8000;
+const uint32_t APPLICATION_ADDRESS = 0x10000;
+
+
+#define HIGHER_BAUD_RATE 230400
+
+esp_loader_error_t flash_binary(const unsigned char *bin, size_t size, size_t address)
+{
+    esp_loader_error_t err;
+    int32_t packet_number = 0;
+    static uint8_t payload[1024];
+    const unsigned char *bin_addr = bin;
+
+    printf("Erasing flash...");
+    err = esp_loader_flash_start(address, size, sizeof(payload));
+    if (err != ESP_LOADER_SUCCESS) {
+        printf("Erasing flash failed with error %d.\n", err);
+        return err;
+    }
+    printf("Start programming");
+
+    while (size > 0) {
+        size_t to_read = MIN(size, sizeof(payload));
+        memcpy(payload, bin_addr, to_read);
+
+        err = esp_loader_flash_write(payload, to_read);
+        if (err != ESP_LOADER_SUCCESS) {
+            printf("Packet could not be written\n");
+            return err;
+        }
+
+        printf("packet: %ld  written: %u B\n", packet_number++, to_read);
+
+        size -= to_read;
+        bin_addr += to_read;
+    };
+
+    printf("Finished programming\n");
+
+#if MD5_ENABLED
+    err = esp_loader_flash_verify();
+    if (err != ESP_LOADER_SUCCESS) {
+        printf("MD5 does not match. err: %d\n", err);
+        return err;
+    }
+    printf("Flash verified\n");
+#endif
+    
+    return ESP_LOADER_SUCCESS;
+}
+
+HAL_StatusTypeDef connect_to_target()
+{
+    loader_port_stm32_init(&huart1, GPIOB, TARGET_IO0_Pin, GPIOB, TARGET_RST_Pin);
+
+    esp_loader_connect_args_t connect_config = ESP_LOADER_CONNECT_DEFAULT();
+
+    esp_loader_error_t err = esp_loader_connect(&connect_config);
+    if (err != ESP_LOADER_SUCCESS) {
+        printf("Cannot connect to target. Error: %u\n", err);
+        return err;
+    }
+    printf("Connected to target\n");
+
+    err = esp_loader_change_baudrate(HIGHER_BAUD_RATE);
+    if (err != ESP_LOADER_SUCCESS) {
+        printf("Unable to change baud rate on target.");
+        return err;
+    }
+
+    err = loader_port_change_baudrate(HIGHER_BAUD_RATE);
+    if (err != ESP_LOADER_SUCCESS) {
+        printf("Unable to change baud rate.");
+        return err;
+    }
+    printf("Baudrate changed\n");
+
+    return HAL_OK;
+}
+
+void flash_images()
+{
+    if(connect_to_target() == HAL_OK) {
+        flash_binary(bootloader_bin, bootloader_bin_size, BOOTLOADER_ADDRESS);
+        flash_binary(partition_table_bin, partition_table_bin_size, PARTITION_ADDRESS);
+        flash_binary(hello_world_bin, hello_world_bin_size, APPLICATION_ADDRESS);
+    }
+}
+
+
+int main(void)
+{
+  HAL_Init();
+  SystemClock_Config();
+  MX_GPIO_Init();
+  MX_USART1_UART_Init();
+  MX_USART2_UART_Init();
+
+  flash_images();
+  while (1) { }
+}
+
+
+void SystemClock_Config(void)
+{
+  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
+  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
+
+  /** Configure the main internal regulator output voltage 
+  */
+  __HAL_RCC_PWR_CLK_ENABLE();
+  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
+  /** Initializes the CPU, AHB and APB busses clocks 
+  */
+  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
+  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
+  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
+  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
+  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  /** Initializes the CPU, AHB and APB busses clocks 
+  */
+  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
+                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
+  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
+  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
+  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
+
+  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
+  {
+    Error_Handler();
+  }
+}
+
+static void MX_USART1_UART_Init(void)
+{
+  huart1.Instance = USART1;
+  huart1.Init.BaudRate = 115200;
+  huart1.Init.WordLength = UART_WORDLENGTH_8B;
+  huart1.Init.StopBits = UART_STOPBITS_1;
+  huart1.Init.Parity = UART_PARITY_NONE;
+  huart1.Init.Mode = UART_MODE_TX_RX;
+  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
+  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
+  if (HAL_UART_Init(&huart1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+}
+
+static void MX_USART2_UART_Init(void)
+{
+  huart2.Instance = USART2;
+  huart2.Init.BaudRate = 115200;
+  huart2.Init.WordLength = UART_WORDLENGTH_8B;
+  huart2.Init.StopBits = UART_STOPBITS_1;
+  huart2.Init.Parity = UART_PARITY_NONE;
+  huart2.Init.Mode = UART_MODE_TX_RX;
+  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
+  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
+  if (HAL_UART_Init(&huart2) != HAL_OK)
+  {
+    Error_Handler();
+  }
+}
+
+static void MX_GPIO_Init(void)
+{
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+
+  /* GPIO Ports Clock Enable */
+  __HAL_RCC_GPIOD_CLK_ENABLE();
+  __HAL_RCC_GPIOB_CLK_ENABLE();
+
+  /*Configure GPIO pin Output Level */
+  HAL_GPIO_WritePin(GPIOD, GREEN_LED_Pin|ORANGE_LED_Pin|RED_LED_Pin|BLUE_LED_Pin, GPIO_PIN_RESET);
+
+  /*Configure GPIO pin Output Level */
+  HAL_GPIO_WritePin(GPIOB, TARGET_RST_Pin|TARGET_IO0_Pin, GPIO_PIN_RESET);
+
+  /*Configure GPIO pins : GREEN_LED_Pin ORANGE_LED_Pin RED_LED_Pin BLUE_LED_Pin */
+  GPIO_InitStruct.Pin = GREEN_LED_Pin|ORANGE_LED_Pin|RED_LED_Pin|BLUE_LED_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
+
+  /*Configure GPIO pins : PB4 PB5 */
+  GPIO_InitStruct.Pin = TARGET_RST_Pin|TARGET_IO0_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+}
+
+/**
+  * @brief  This function is executed in case of error occurrence.
+  * @retval None
+  */
+void Error_Handler(void)
+{
+  /* User can add his own implementation to report the HAL error return state */
+}
+
+#ifdef  USE_FULL_ASSERT
+/**
+  * @brief  Reports the name of the source file and the source line number
+  *         where the assert_param error has occurred.
+  * @param  file: pointer to the source file name
+  * @param  line: assert_param error line source number
+  * @retval None
+  */
+void assert_failed(uint8_t *file, uint32_t line)
+{ 
+  /* User can add his own implementation to report the file name and line number,
+     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
+}
+#endif /* USE_FULL_ASSERT */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 109 - 0
examples/stm32_example/Src/stm32f4xx_hal_msp.c

@@ -0,0 +1,109 @@
+/**
+  ******************************************************************************
+  * File Name          : stm32f4xx_hal_msp.c
+  * Description        : This file provides code for the MSP Initialization 
+  *                      and de-Initialization codes.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under BSD 3-Clause license,
+  * the "License"; You may not use this file except in compliance with the
+  * License. You may obtain a copy of the License at:
+  *                        opensource.org/licenses/BSD-3-Clause
+  *
+  ******************************************************************************
+  */
+
+#include "main.h"
+
+void HAL_MspInit(void)
+{
+  __HAL_RCC_SYSCFG_CLK_ENABLE();
+  __HAL_RCC_PWR_CLK_ENABLE();
+}
+
+/**
+* @brief UART MSP Initialization
+* This function configures the hardware resources used in this example
+* @param huart: UART handle pointer
+* @retval None
+*/
+void HAL_UART_MspInit(UART_HandleTypeDef* huart)
+{
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+  if(huart->Instance==USART1)
+  {
+    /* Peripheral clock enable */
+    __HAL_RCC_USART1_CLK_ENABLE();
+  
+    __HAL_RCC_GPIOB_CLK_ENABLE();
+    /**USART1 GPIO Configuration    
+    PB6     ------> USART1_TX
+    PB7     ------> USART1_RX 
+    */
+    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
+    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+  }
+  else if(huart->Instance==USART2)
+  {
+    /* Peripheral clock enable */
+    __HAL_RCC_USART2_CLK_ENABLE();
+  
+    __HAL_RCC_GPIOD_CLK_ENABLE();
+    /**USART2 GPIO Configuration    
+    PD5     ------> USART2_TX
+    PD6     ------> USART2_RX 
+    */
+    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+    GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
+    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
+  }
+
+}
+
+/**
+* @brief UART MSP De-Initialization
+* This function freeze the hardware resources used in this example
+* @param huart: UART handle pointer
+* @retval None
+*/
+void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
+{
+  if(huart->Instance==USART1)
+  {
+    /* Peripheral clock disable */
+    __HAL_RCC_USART1_CLK_DISABLE();
+  
+    /**USART1 GPIO Configuration    
+    PB6     ------> USART1_TX
+    PB7     ------> USART1_RX 
+    */
+    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6|GPIO_PIN_7);
+
+  }
+  else if(huart->Instance==USART2)
+  {
+    /* Peripheral clock disable */
+    __HAL_RCC_USART2_CLK_DISABLE();
+  
+    /**USART2 GPIO Configuration    
+    PD5     ------> USART2_TX
+    PD6     ------> USART2_RX 
+    */
+    HAL_GPIO_DeInit(GPIOD, GPIO_PIN_5|GPIO_PIN_6);
+  }
+
+}
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 204 - 0
examples/stm32_example/Src/stm32f4xx_it.c

@@ -0,0 +1,204 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file    stm32f4xx_it.c
+  * @brief   Interrupt Service Routines.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under BSD 3-Clause license,
+  * the "License"; You may not use this file except in compliance with the
+  * License. You may obtain a copy of the License at:
+  *                        opensource.org/licenses/BSD-3-Clause
+  *
+  ******************************************************************************
+  */
+/* USER CODE END Header */
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+#include "stm32f4xx_it.h"
+/* Private includes ----------------------------------------------------------*/
+/* USER CODE BEGIN Includes */
+#include <stdio.h>
+/* USER CODE END Includes */
+
+/* Private typedef -----------------------------------------------------------*/
+/* USER CODE BEGIN TD */
+
+/* USER CODE END TD */
+
+/* Private define ------------------------------------------------------------*/
+/* USER CODE BEGIN PD */
+ 
+/* USER CODE END PD */
+
+/* Private macro -------------------------------------------------------------*/
+/* USER CODE BEGIN PM */
+
+/* USER CODE END PM */
+
+/* Private variables ---------------------------------------------------------*/
+/* USER CODE BEGIN PV */
+
+/* USER CODE END PV */
+
+/* Private function prototypes -----------------------------------------------*/
+/* USER CODE BEGIN PFP */
+
+/* USER CODE END PFP */
+
+/* Private user code ---------------------------------------------------------*/
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+/* External variables --------------------------------------------------------*/
+
+/* USER CODE BEGIN EV */
+
+/* USER CODE END EV */
+
+/******************************************************************************/
+/*           Cortex-M4 Processor Interruption and Exception Handlers          */ 
+/******************************************************************************/
+/**
+  * @brief This function handles Non maskable interrupt.
+  */
+void NMI_Handler(void)
+{
+  /* USER CODE BEGIN NonMaskableInt_IRQn 0 */
+
+  /* USER CODE END NonMaskableInt_IRQn 0 */
+  /* USER CODE BEGIN NonMaskableInt_IRQn 1 */
+
+  /* USER CODE END NonMaskableInt_IRQn 1 */
+}
+
+/**
+  * @brief This function handles Hard fault interrupt.
+  */
+void HardFault_Handler(void)
+{
+  /* USER CODE BEGIN HardFault_IRQn 0 */
+
+  /* USER CODE END HardFault_IRQn 0 */
+  while (1)
+  {
+    /* USER CODE BEGIN W1_HardFault_IRQn 0 */
+    /* USER CODE END W1_HardFault_IRQn 0 */
+  }
+}
+
+/**
+  * @brief This function handles Memory management fault.
+  */
+void MemManage_Handler(void)
+{
+  /* USER CODE BEGIN MemoryManagement_IRQn 0 */
+
+  /* USER CODE END MemoryManagement_IRQn 0 */
+  while (1)
+  {
+    /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
+    /* USER CODE END W1_MemoryManagement_IRQn 0 */
+  }
+}
+
+/**
+  * @brief This function handles Pre-fetch fault, memory access fault.
+  */
+void BusFault_Handler(void)
+{
+  /* USER CODE BEGIN BusFault_IRQn 0 */
+
+  /* USER CODE END BusFault_IRQn 0 */
+  while (1)
+  {
+    /* USER CODE BEGIN W1_BusFault_IRQn 0 */
+    /* USER CODE END W1_BusFault_IRQn 0 */
+  }
+}
+
+/**
+  * @brief This function handles Undefined instruction or illegal state.
+  */
+void UsageFault_Handler(void)
+{
+  /* USER CODE BEGIN UsageFault_IRQn 0 */
+
+  /* USER CODE END UsageFault_IRQn 0 */
+  while (1)
+  {
+    /* USER CODE BEGIN W1_UsageFault_IRQn 0 */
+    /* USER CODE END W1_UsageFault_IRQn 0 */
+  }
+}
+
+/**
+  * @brief This function handles System service call via SWI instruction.
+  */
+void SVC_Handler(void)
+{
+  /* USER CODE BEGIN SVCall_IRQn 0 */
+
+  /* USER CODE END SVCall_IRQn 0 */
+  /* USER CODE BEGIN SVCall_IRQn 1 */
+
+  /* USER CODE END SVCall_IRQn 1 */
+}
+
+/**
+  * @brief This function handles Debug monitor.
+  */
+void DebugMon_Handler(void)
+{
+  /* USER CODE BEGIN DebugMonitor_IRQn 0 */
+
+  /* USER CODE END DebugMonitor_IRQn 0 */
+  /* USER CODE BEGIN DebugMonitor_IRQn 1 */
+
+  /* USER CODE END DebugMonitor_IRQn 1 */
+}
+
+/**
+  * @brief This function handles Pendable request for system service.
+  */
+void PendSV_Handler(void)
+{
+  /* USER CODE BEGIN PendSV_IRQn 0 */
+
+  /* USER CODE END PendSV_IRQn 0 */
+  /* USER CODE BEGIN PendSV_IRQn 1 */
+
+  /* USER CODE END PendSV_IRQn 1 */
+}
+
+/**
+  * @brief This function handles System tick timer.
+  */
+void SysTick_Handler(void)
+{
+  /* USER CODE BEGIN SysTick_IRQn 0 */
+
+  /* USER CODE END SysTick_IRQn 0 */
+  HAL_IncTick();
+  /* USER CODE BEGIN SysTick_IRQn 1 */
+
+  /* USER CODE END SysTick_IRQn 1 */
+}
+
+/******************************************************************************/
+/* STM32F4xx Peripheral Interrupt Handlers                                    */
+/* Add here the Interrupt Handlers for the used peripherals.                  */
+/* For the available peripheral interrupt handler names,                      */
+/* please refer to the startup file (startup_stm32f4xx.s).                    */
+/******************************************************************************/
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 727 - 0
examples/stm32_example/Src/system_stm32f4xx.c

@@ -0,0 +1,727 @@
+/**
+  ******************************************************************************
+  * @file    system_stm32f4xx.c
+  * @author  MCD Application Team
+  * @brief   CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
+  *
+  *   This file provides two functions and one global variable to be called from 
+  *   user application:
+  *      - SystemInit(): This function is called at startup just after reset and 
+  *                      before branch to main program. This call is made inside
+  *                      the "startup_stm32f4xx.s" file.
+  *
+  *      - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+  *                                  by the user application to setup the SysTick 
+  *                                  timer or configure other parameters.
+  *                                     
+  *      - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
+  *                                 be called whenever the core clock is changed
+  *                                 during program execution.
+  *
+  *
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under BSD 3-Clause license,
+  * the "License"; You may not use this file except in compliance with the
+  * License. You may obtain a copy of the License at:
+  *                        opensource.org/licenses/BSD-3-Clause
+  *
+  ******************************************************************************
+  */
+
+/** @addtogroup CMSIS
+  * @{
+  */
+
+/** @addtogroup stm32f4xx_system
+  * @{
+  */  
+  
+/** @addtogroup STM32F4xx_System_Private_Includes
+  * @{
+  */
+
+
+#include "stm32f4xx.h"
+
+#if !defined  (HSE_VALUE) 
+  #define HSE_VALUE    ((uint32_t)25000000) /*!< Default value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined  (HSI_VALUE)
+  #define HSI_VALUE    ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI_VALUE */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32F4xx_System_Private_TypesDefinitions
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32F4xx_System_Private_Defines
+  * @{
+  */
+
+/************************* Miscellaneous Configuration ************************/
+/*!< Uncomment the following line if you need to use external SRAM or SDRAM as data memory  */
+#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\
+ || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
+ || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx)
+/* #define DATA_IN_ExtSRAM */
+#endif /* STM32F40xxx || STM32F41xxx || STM32F42xxx || STM32F43xxx || STM32F469xx || STM32F479xx ||\
+          STM32F412Zx || STM32F412Vx */
+ 
+#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
+ || defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx)
+/* #define DATA_IN_ExtSDRAM */
+#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx ||\
+          STM32F479xx */
+
+/*!< Uncomment the following line if you need to relocate your vector Table in
+     Internal SRAM. */
+/* #define VECT_TAB_SRAM */
+#define VECT_TAB_OFFSET  0x00 /*!< Vector Table base offset field. 
+                                   This value must be a multiple of 0x200. */
+/******************************************************************************/
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32F4xx_System_Private_Macros
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32F4xx_System_Private_Variables
+  * @{
+  */
+  /* This variable is updated in three ways:
+      1) by calling CMSIS function SystemCoreClockUpdate()
+      2) by calling HAL API function HAL_RCC_GetHCLKFreq()
+      3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency 
+         Note: If you use this function to configure the system clock; then there
+               is no need to call the 2 first functions listed above, since SystemCoreClock
+               variable is updated automatically.
+  */
+uint32_t SystemCoreClock = 16000000;
+const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+const uint8_t APBPrescTable[8]  = {0, 0, 0, 0, 1, 2, 3, 4};
+/**
+  * @}
+  */
+
+/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes
+  * @{
+  */
+
+#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
+  static void SystemInit_ExtMemCtl(void); 
+#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32F4xx_System_Private_Functions
+  * @{
+  */
+
+/**
+  * @brief  Setup the microcontroller system
+  *         Initialize the FPU setting, vector table location and External memory 
+  *         configuration.
+  * @param  None
+  * @retval None
+  */
+void SystemInit(void)
+{
+  /* FPU settings ------------------------------------------------------------*/
+  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
+  #endif
+
+#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
+  SystemInit_ExtMemCtl(); 
+#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
+
+  /* Configure the Vector Table location add offset address ------------------*/
+#ifdef VECT_TAB_SRAM
+  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
+#else
+  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
+#endif
+}
+
+/**
+   * @brief  Update SystemCoreClock variable according to Clock Register Values.
+  *         The SystemCoreClock variable contains the core clock (HCLK), it can
+  *         be used by the user application to setup the SysTick timer or configure
+  *         other parameters.
+  *           
+  * @note   Each time the core clock (HCLK) changes, this function must be called
+  *         to update SystemCoreClock variable value. Otherwise, any configuration
+  *         based on this variable will be incorrect.         
+  *     
+  * @note   - The system frequency computed by this function is not the real 
+  *           frequency in the chip. It is calculated based on the predefined 
+  *           constant and the selected clock source:
+  *             
+  *           - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
+  *                                              
+  *           - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
+  *                          
+  *           - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) 
+  *             or HSI_VALUE(*) multiplied/divided by the PLL factors.
+  *         
+  *         (*) HSI_VALUE is a constant defined in stm32f4xx_hal_conf.h file (default value
+  *             16 MHz) but the real value may vary depending on the variations
+  *             in voltage and temperature.   
+  *    
+  *         (**) HSE_VALUE is a constant defined in stm32f4xx_hal_conf.h file (its value
+  *              depends on the application requirements), user has to ensure that HSE_VALUE
+  *              is same as the real frequency of the crystal used. Otherwise, this function
+  *              may have wrong result.
+  *                
+  *         - The result of this function could be not correct when using fractional
+  *           value for HSE crystal.
+  *     
+  * @param  None
+  * @retval None
+  */
+void SystemCoreClockUpdate(void)
+{
+  uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
+  
+  /* Get SYSCLK source -------------------------------------------------------*/
+  tmp = RCC->CFGR & RCC_CFGR_SWS;
+
+  switch (tmp)
+  {
+    case 0x00:  /* HSI used as system clock source */
+      SystemCoreClock = HSI_VALUE;
+      break;
+    case 0x04:  /* HSE used as system clock source */
+      SystemCoreClock = HSE_VALUE;
+      break;
+    case 0x08:  /* PLL used as system clock source */
+
+      /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
+         SYSCLK = PLL_VCO / PLL_P
+         */    
+      pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
+      pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
+      
+      if (pllsource != 0)
+      {
+        /* HSE used as PLL clock source */
+        pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+      }
+      else
+      {
+        /* HSI used as PLL clock source */
+        pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+      }
+
+      pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
+      SystemCoreClock = pllvco/pllp;
+      break;
+    default:
+      SystemCoreClock = HSI_VALUE;
+      break;
+  }
+  /* Compute HCLK frequency --------------------------------------------------*/
+  /* Get HCLK prescaler */
+  tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
+  /* HCLK frequency */
+  SystemCoreClock >>= tmp;
+}
+
+#if defined (DATA_IN_ExtSRAM) && defined (DATA_IN_ExtSDRAM)
+#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
+ || defined(STM32F469xx) || defined(STM32F479xx)
+/**
+  * @brief  Setup the external memory controller.
+  *         Called in startup_stm32f4xx.s before jump to main.
+  *         This function configures the external memories (SRAM/SDRAM)
+  *         This SRAM/SDRAM will be used as program data memory (including heap and stack).
+  * @param  None
+  * @retval None
+  */
+void SystemInit_ExtMemCtl(void)
+{
+  __IO uint32_t tmp = 0x00;
+
+  register uint32_t tmpreg = 0, timeout = 0xFFFF;
+  register __IO uint32_t index;
+
+  /* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface clock */
+  RCC->AHB1ENR |= 0x000001F8;
+
+  /* Delay after an RCC peripheral clock enabling */
+  tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);
+  
+  /* Connect PDx pins to FMC Alternate function */
+  GPIOD->AFR[0]  = 0x00CCC0CC;
+  GPIOD->AFR[1]  = 0xCCCCCCCC;
+  /* Configure PDx pins in Alternate function mode */  
+  GPIOD->MODER   = 0xAAAA0A8A;
+  /* Configure PDx pins speed to 100 MHz */  
+  GPIOD->OSPEEDR = 0xFFFF0FCF;
+  /* Configure PDx pins Output type to push-pull */  
+  GPIOD->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PDx pins */ 
+  GPIOD->PUPDR   = 0x00000000;
+
+  /* Connect PEx pins to FMC Alternate function */
+  GPIOE->AFR[0]  = 0xC00CC0CC;
+  GPIOE->AFR[1]  = 0xCCCCCCCC;
+  /* Configure PEx pins in Alternate function mode */ 
+  GPIOE->MODER   = 0xAAAA828A;
+  /* Configure PEx pins speed to 100 MHz */ 
+  GPIOE->OSPEEDR = 0xFFFFC3CF;
+  /* Configure PEx pins Output type to push-pull */  
+  GPIOE->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PEx pins */ 
+  GPIOE->PUPDR   = 0x00000000;
+  
+  /* Connect PFx pins to FMC Alternate function */
+  GPIOF->AFR[0]  = 0xCCCCCCCC;
+  GPIOF->AFR[1]  = 0xCCCCCCCC;
+  /* Configure PFx pins in Alternate function mode */   
+  GPIOF->MODER   = 0xAA800AAA;
+  /* Configure PFx pins speed to 50 MHz */ 
+  GPIOF->OSPEEDR = 0xAA800AAA;
+  /* Configure PFx pins Output type to push-pull */  
+  GPIOF->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PFx pins */ 
+  GPIOF->PUPDR   = 0x00000000;
+
+  /* Connect PGx pins to FMC Alternate function */
+  GPIOG->AFR[0]  = 0xCCCCCCCC;
+  GPIOG->AFR[1]  = 0xCCCCCCCC;
+  /* Configure PGx pins in Alternate function mode */ 
+  GPIOG->MODER   = 0xAAAAAAAA;
+  /* Configure PGx pins speed to 50 MHz */ 
+  GPIOG->OSPEEDR = 0xAAAAAAAA;
+  /* Configure PGx pins Output type to push-pull */  
+  GPIOG->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PGx pins */ 
+  GPIOG->PUPDR   = 0x00000000;
+  
+  /* Connect PHx pins to FMC Alternate function */
+  GPIOH->AFR[0]  = 0x00C0CC00;
+  GPIOH->AFR[1]  = 0xCCCCCCCC;
+  /* Configure PHx pins in Alternate function mode */ 
+  GPIOH->MODER   = 0xAAAA08A0;
+  /* Configure PHx pins speed to 50 MHz */ 
+  GPIOH->OSPEEDR = 0xAAAA08A0;
+  /* Configure PHx pins Output type to push-pull */  
+  GPIOH->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PHx pins */ 
+  GPIOH->PUPDR   = 0x00000000;
+  
+  /* Connect PIx pins to FMC Alternate function */
+  GPIOI->AFR[0]  = 0xCCCCCCCC;
+  GPIOI->AFR[1]  = 0x00000CC0;
+  /* Configure PIx pins in Alternate function mode */ 
+  GPIOI->MODER   = 0x0028AAAA;
+  /* Configure PIx pins speed to 50 MHz */ 
+  GPIOI->OSPEEDR = 0x0028AAAA;
+  /* Configure PIx pins Output type to push-pull */  
+  GPIOI->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PIx pins */ 
+  GPIOI->PUPDR   = 0x00000000;
+  
+/*-- FMC Configuration -------------------------------------------------------*/
+  /* Enable the FMC interface clock */
+  RCC->AHB3ENR |= 0x00000001;
+  /* Delay after an RCC peripheral clock enabling */
+  tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
+
+  FMC_Bank5_6->SDCR[0] = 0x000019E4;
+  FMC_Bank5_6->SDTR[0] = 0x01115351;      
+  
+  /* SDRAM initialization sequence */
+  /* Clock enable command */
+  FMC_Bank5_6->SDCMR = 0x00000011; 
+  tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
+  while((tmpreg != 0) && (timeout-- > 0))
+  {
+    tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
+  }
+
+  /* Delay */
+  for (index = 0; index<1000; index++);
+  
+  /* PALL command */
+  FMC_Bank5_6->SDCMR = 0x00000012;           
+  timeout = 0xFFFF;
+  while((tmpreg != 0) && (timeout-- > 0))
+  {
+    tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
+  }
+  
+  /* Auto refresh command */
+  FMC_Bank5_6->SDCMR = 0x00000073;
+  timeout = 0xFFFF;
+  while((tmpreg != 0) && (timeout-- > 0))
+  {
+    tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
+  }
+ 
+  /* MRD register program */
+  FMC_Bank5_6->SDCMR = 0x00046014;
+  timeout = 0xFFFF;
+  while((tmpreg != 0) && (timeout-- > 0))
+  {
+    tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
+  } 
+  
+  /* Set refresh count */
+  tmpreg = FMC_Bank5_6->SDRTR;
+  FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1));
+  
+  /* Disable write protection */
+  tmpreg = FMC_Bank5_6->SDCR[0]; 
+  FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF);
+
+#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)
+  /* Configure and enable Bank1_SRAM2 */
+  FMC_Bank1->BTCR[2]  = 0x00001011;
+  FMC_Bank1->BTCR[3]  = 0x00000201;
+  FMC_Bank1E->BWTR[2] = 0x0fffffff;
+#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */ 
+#if defined(STM32F469xx) || defined(STM32F479xx)
+  /* Configure and enable Bank1_SRAM2 */
+  FMC_Bank1->BTCR[2]  = 0x00001091;
+  FMC_Bank1->BTCR[3]  = 0x00110212;
+  FMC_Bank1E->BWTR[2] = 0x0fffffff;
+#endif /* STM32F469xx || STM32F479xx */
+
+  (void)(tmp); 
+}
+#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */
+#elif defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
+/**
+  * @brief  Setup the external memory controller.
+  *         Called in startup_stm32f4xx.s before jump to main.
+  *         This function configures the external memories (SRAM/SDRAM)
+  *         This SRAM/SDRAM will be used as program data memory (including heap and stack).
+  * @param  None
+  * @retval None
+  */
+void SystemInit_ExtMemCtl(void)
+{
+  __IO uint32_t tmp = 0x00;
+#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
+ || defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx)
+#if defined (DATA_IN_ExtSDRAM)
+  register uint32_t tmpreg = 0, timeout = 0xFFFF;
+  register __IO uint32_t index;
+
+#if defined(STM32F446xx)
+  /* Enable GPIOA, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG interface
+      clock */
+  RCC->AHB1ENR |= 0x0000007D;
+#else
+  /* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface 
+      clock */
+  RCC->AHB1ENR |= 0x000001F8;
+#endif /* STM32F446xx */  
+  /* Delay after an RCC peripheral clock enabling */
+  tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);
+  
+#if defined(STM32F446xx)
+  /* Connect PAx pins to FMC Alternate function */
+  GPIOA->AFR[0]  |= 0xC0000000;
+  GPIOA->AFR[1]  |= 0x00000000;
+  /* Configure PDx pins in Alternate function mode */
+  GPIOA->MODER   |= 0x00008000;
+  /* Configure PDx pins speed to 50 MHz */
+  GPIOA->OSPEEDR |= 0x00008000;
+  /* Configure PDx pins Output type to push-pull */
+  GPIOA->OTYPER  |= 0x00000000;
+  /* No pull-up, pull-down for PDx pins */
+  GPIOA->PUPDR   |= 0x00000000;
+
+  /* Connect PCx pins to FMC Alternate function */
+  GPIOC->AFR[0]  |= 0x00CC0000;
+  GPIOC->AFR[1]  |= 0x00000000;
+  /* Configure PDx pins in Alternate function mode */
+  GPIOC->MODER   |= 0x00000A00;
+  /* Configure PDx pins speed to 50 MHz */
+  GPIOC->OSPEEDR |= 0x00000A00;
+  /* Configure PDx pins Output type to push-pull */
+  GPIOC->OTYPER  |= 0x00000000;
+  /* No pull-up, pull-down for PDx pins */
+  GPIOC->PUPDR   |= 0x00000000;
+#endif /* STM32F446xx */
+
+  /* Connect PDx pins to FMC Alternate function */
+  GPIOD->AFR[0]  = 0x000000CC;
+  GPIOD->AFR[1]  = 0xCC000CCC;
+  /* Configure PDx pins in Alternate function mode */  
+  GPIOD->MODER   = 0xA02A000A;
+  /* Configure PDx pins speed to 50 MHz */  
+  GPIOD->OSPEEDR = 0xA02A000A;
+  /* Configure PDx pins Output type to push-pull */  
+  GPIOD->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PDx pins */ 
+  GPIOD->PUPDR   = 0x00000000;
+
+  /* Connect PEx pins to FMC Alternate function */
+  GPIOE->AFR[0]  = 0xC00000CC;
+  GPIOE->AFR[1]  = 0xCCCCCCCC;
+  /* Configure PEx pins in Alternate function mode */ 
+  GPIOE->MODER   = 0xAAAA800A;
+  /* Configure PEx pins speed to 50 MHz */ 
+  GPIOE->OSPEEDR = 0xAAAA800A;
+  /* Configure PEx pins Output type to push-pull */  
+  GPIOE->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PEx pins */ 
+  GPIOE->PUPDR   = 0x00000000;
+
+  /* Connect PFx pins to FMC Alternate function */
+  GPIOF->AFR[0]  = 0xCCCCCCCC;
+  GPIOF->AFR[1]  = 0xCCCCCCCC;
+  /* Configure PFx pins in Alternate function mode */   
+  GPIOF->MODER   = 0xAA800AAA;
+  /* Configure PFx pins speed to 50 MHz */ 
+  GPIOF->OSPEEDR = 0xAA800AAA;
+  /* Configure PFx pins Output type to push-pull */  
+  GPIOF->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PFx pins */ 
+  GPIOF->PUPDR   = 0x00000000;
+
+  /* Connect PGx pins to FMC Alternate function */
+  GPIOG->AFR[0]  = 0xCCCCCCCC;
+  GPIOG->AFR[1]  = 0xCCCCCCCC;
+  /* Configure PGx pins in Alternate function mode */ 
+  GPIOG->MODER   = 0xAAAAAAAA;
+  /* Configure PGx pins speed to 50 MHz */ 
+  GPIOG->OSPEEDR = 0xAAAAAAAA;
+  /* Configure PGx pins Output type to push-pull */  
+  GPIOG->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PGx pins */ 
+  GPIOG->PUPDR   = 0x00000000;
+
+#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
+ || defined(STM32F469xx) || defined(STM32F479xx)  
+  /* Connect PHx pins to FMC Alternate function */
+  GPIOH->AFR[0]  = 0x00C0CC00;
+  GPIOH->AFR[1]  = 0xCCCCCCCC;
+  /* Configure PHx pins in Alternate function mode */ 
+  GPIOH->MODER   = 0xAAAA08A0;
+  /* Configure PHx pins speed to 50 MHz */ 
+  GPIOH->OSPEEDR = 0xAAAA08A0;
+  /* Configure PHx pins Output type to push-pull */  
+  GPIOH->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PHx pins */ 
+  GPIOH->PUPDR   = 0x00000000;
+  
+  /* Connect PIx pins to FMC Alternate function */
+  GPIOI->AFR[0]  = 0xCCCCCCCC;
+  GPIOI->AFR[1]  = 0x00000CC0;
+  /* Configure PIx pins in Alternate function mode */ 
+  GPIOI->MODER   = 0x0028AAAA;
+  /* Configure PIx pins speed to 50 MHz */ 
+  GPIOI->OSPEEDR = 0x0028AAAA;
+  /* Configure PIx pins Output type to push-pull */  
+  GPIOI->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PIx pins */ 
+  GPIOI->PUPDR   = 0x00000000;
+#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */
+  
+/*-- FMC Configuration -------------------------------------------------------*/
+  /* Enable the FMC interface clock */
+  RCC->AHB3ENR |= 0x00000001;
+  /* Delay after an RCC peripheral clock enabling */
+  tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
+
+  /* Configure and enable SDRAM bank1 */
+#if defined(STM32F446xx)
+  FMC_Bank5_6->SDCR[0] = 0x00001954;
+#else  
+  FMC_Bank5_6->SDCR[0] = 0x000019E4;
+#endif /* STM32F446xx */
+  FMC_Bank5_6->SDTR[0] = 0x01115351;      
+  
+  /* SDRAM initialization sequence */
+  /* Clock enable command */
+  FMC_Bank5_6->SDCMR = 0x00000011; 
+  tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
+  while((tmpreg != 0) && (timeout-- > 0))
+  {
+    tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
+  }
+
+  /* Delay */
+  for (index = 0; index<1000; index++);
+  
+  /* PALL command */
+  FMC_Bank5_6->SDCMR = 0x00000012;           
+  timeout = 0xFFFF;
+  while((tmpreg != 0) && (timeout-- > 0))
+  {
+    tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
+  }
+  
+  /* Auto refresh command */
+#if defined(STM32F446xx)
+  FMC_Bank5_6->SDCMR = 0x000000F3;
+#else  
+  FMC_Bank5_6->SDCMR = 0x00000073;
+#endif /* STM32F446xx */
+  timeout = 0xFFFF;
+  while((tmpreg != 0) && (timeout-- > 0))
+  {
+    tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
+  }
+ 
+  /* MRD register program */
+#if defined(STM32F446xx)
+  FMC_Bank5_6->SDCMR = 0x00044014;
+#else  
+  FMC_Bank5_6->SDCMR = 0x00046014;
+#endif /* STM32F446xx */
+  timeout = 0xFFFF;
+  while((tmpreg != 0) && (timeout-- > 0))
+  {
+    tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
+  } 
+  
+  /* Set refresh count */
+  tmpreg = FMC_Bank5_6->SDRTR;
+#if defined(STM32F446xx)
+  FMC_Bank5_6->SDRTR = (tmpreg | (0x0000050C<<1));
+#else    
+  FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1));
+#endif /* STM32F446xx */
+  
+  /* Disable write protection */
+  tmpreg = FMC_Bank5_6->SDCR[0]; 
+  FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF);
+#endif /* DATA_IN_ExtSDRAM */
+#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx || STM32F479xx */
+
+#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\
+ || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
+ || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx)
+
+#if defined(DATA_IN_ExtSRAM)
+/*-- GPIOs Configuration -----------------------------------------------------*/
+   /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */
+  RCC->AHB1ENR   |= 0x00000078;
+  /* Delay after an RCC peripheral clock enabling */
+  tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIODEN);
+  
+  /* Connect PDx pins to FMC Alternate function */
+  GPIOD->AFR[0]  = 0x00CCC0CC;
+  GPIOD->AFR[1]  = 0xCCCCCCCC;
+  /* Configure PDx pins in Alternate function mode */  
+  GPIOD->MODER   = 0xAAAA0A8A;
+  /* Configure PDx pins speed to 100 MHz */  
+  GPIOD->OSPEEDR = 0xFFFF0FCF;
+  /* Configure PDx pins Output type to push-pull */  
+  GPIOD->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PDx pins */ 
+  GPIOD->PUPDR   = 0x00000000;
+
+  /* Connect PEx pins to FMC Alternate function */
+  GPIOE->AFR[0]  = 0xC00CC0CC;
+  GPIOE->AFR[1]  = 0xCCCCCCCC;
+  /* Configure PEx pins in Alternate function mode */ 
+  GPIOE->MODER   = 0xAAAA828A;
+  /* Configure PEx pins speed to 100 MHz */ 
+  GPIOE->OSPEEDR = 0xFFFFC3CF;
+  /* Configure PEx pins Output type to push-pull */  
+  GPIOE->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PEx pins */ 
+  GPIOE->PUPDR   = 0x00000000;
+
+  /* Connect PFx pins to FMC Alternate function */
+  GPIOF->AFR[0]  = 0x00CCCCCC;
+  GPIOF->AFR[1]  = 0xCCCC0000;
+  /* Configure PFx pins in Alternate function mode */   
+  GPIOF->MODER   = 0xAA000AAA;
+  /* Configure PFx pins speed to 100 MHz */ 
+  GPIOF->OSPEEDR = 0xFF000FFF;
+  /* Configure PFx pins Output type to push-pull */  
+  GPIOF->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PFx pins */ 
+  GPIOF->PUPDR   = 0x00000000;
+
+  /* Connect PGx pins to FMC Alternate function */
+  GPIOG->AFR[0]  = 0x00CCCCCC;
+  GPIOG->AFR[1]  = 0x000000C0;
+  /* Configure PGx pins in Alternate function mode */ 
+  GPIOG->MODER   = 0x00085AAA;
+  /* Configure PGx pins speed to 100 MHz */ 
+  GPIOG->OSPEEDR = 0x000CAFFF;
+  /* Configure PGx pins Output type to push-pull */  
+  GPIOG->OTYPER  = 0x00000000;
+  /* No pull-up, pull-down for PGx pins */ 
+  GPIOG->PUPDR   = 0x00000000;
+  
+/*-- FMC/FSMC Configuration --------------------------------------------------*/
+  /* Enable the FMC/FSMC interface clock */
+  RCC->AHB3ENR         |= 0x00000001;
+
+#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)
+  /* Delay after an RCC peripheral clock enabling */
+  tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
+  /* Configure and enable Bank1_SRAM2 */
+  FMC_Bank1->BTCR[2]  = 0x00001011;
+  FMC_Bank1->BTCR[3]  = 0x00000201;
+  FMC_Bank1E->BWTR[2] = 0x0fffffff;
+#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */ 
+#if defined(STM32F469xx) || defined(STM32F479xx)
+  /* Delay after an RCC peripheral clock enabling */
+  tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
+  /* Configure and enable Bank1_SRAM2 */
+  FMC_Bank1->BTCR[2]  = 0x00001091;
+  FMC_Bank1->BTCR[3]  = 0x00110212;
+  FMC_Bank1E->BWTR[2] = 0x0fffffff;
+#endif /* STM32F469xx || STM32F479xx */
+#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx)|| defined(STM32F417xx)\
+   || defined(STM32F412Zx) || defined(STM32F412Vx)
+  /* Delay after an RCC peripheral clock enabling */
+  tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FSMCEN);
+  /* Configure and enable Bank1_SRAM2 */
+  FSMC_Bank1->BTCR[2]  = 0x00001011;
+  FSMC_Bank1->BTCR[3]  = 0x00000201;
+  FSMC_Bank1E->BWTR[2] = 0x0FFFFFFF;
+#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F412Zx || STM32F412Vx */
+
+#endif /* DATA_IN_ExtSRAM */
+#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F427xx || STM32F437xx ||\
+          STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx || STM32F412Zx || STM32F412Vx  */ 
+  (void)(tmp); 
+}
+#endif /* DATA_IN_ExtSRAM && DATA_IN_ExtSDRAM */
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

BIN
examples/stm32_example/images/bootloader.bin


BIN
examples/stm32_example/images/hello-world.bin


BIN
examples/stm32_example/images/partition-table.bin


+ 6 - 0
include/esp_loader.h

@@ -17,6 +17,7 @@
 
 #include <stdint.h>
 #include <stdbool.h>
+#include "loader_config.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -30,7 +31,10 @@ typedef enum
     ESP_LOADER_SUCCESS,                /*!< Success */
     ESP_LOADER_ERROR_FAIL,             /*!< Unspecified error */
     ESP_LOADER_ERROR_TIMEOUT,          /*!< Timeout elapsed */
+    ESP_LOADER_ERROR_IMAGE_SIZE,       /*!< Image size to flash is larger than flash size */
     ESP_LOADER_ERROR_INVALID_MD5,      /*!< Computed and receied MD5 does not match */
+    ESP_LOADER_ERROR_INVALID_TARGET,   /*!< Connected target is invalid */
+    ESP_LOADER_ERROR_UNSUPPORTED_CHIP, /*!< Attached chip is not supported */
     ESP_LOADER_ERROR_INVALID_RESPONSE  /*!< Internal error */
 } esp_loader_error_t;
 
@@ -147,7 +151,9 @@ esp_loader_error_t esp_loader_read_register(uint32_t address, uint32_t *reg_valu
   *     - ESP_LOADER_ERROR_TIMEOUT Timeout
   *     - ESP_LOADER_ERROR_INVALID_RESPONSE Internal error
   */
+#ifndef TARGET_ESP8266
 esp_loader_error_t esp_loader_change_baudrate(uint32_t baudrate);
+#endif
 
 /**
   * @brief Verify target's flash integrity by checking MD5.

+ 9 - 0
include/loader_config.h

@@ -23,8 +23,17 @@ extern "C" {
 // When enabled, esp_loader_flash_verify() function can be called to to verify
 // flash integrity. In case verification is unnecessary, this option can be 
 // disabled in order to reduce code size.
+#if !defined MD5_ENABLED
 #define MD5_ENABLED  1
+#endif
+
+#if !defined TARGET_ESP32_S2 && !defined TARGET_ESP8266
+#define TARGET_ESP32 1
+#endif
 
+#if MD5_ENABLED && defined TARGET_ESP8266
+#error "ESP8266 ROM loader does not support MD5 check"
+#endif
 
 #ifdef __cplusplus
 }

+ 0 - 0
port/esp32_uart.c → port/esp32_port.c


+ 168 - 0
port/stm32_port.c

@@ -0,0 +1,168 @@
+/* Copyright 2020 Espressif Systems (Shanghai) PTE 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.
+ */
+
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include "serial_io.h"
+#include "stm32f4xx_hal.h"
+
+// #define SERIAL_DEBUG_ENABLE
+
+static UART_HandleTypeDef *uart;
+static GPIO_TypeDef* gpio_port_io0, *gpio_port_rst;
+static uint16_t gpio_num_io0, gpio_num_rst;
+
+#ifdef SERIAL_DEBUG_ENABLE
+
+static void dec_to_hex_str(const uint8_t dec, uint8_t hex_str[3])
+{
+    static const uint8_t dec_to_hex[] = {
+        '0', '1', '2', '3', '4', '5', '6', '7',
+        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+    };
+
+    hex_str[0] = dec_to_hex[(dec >> 4)];
+    hex_str[1] = dec_to_hex[(dec & 0xF)];
+    hex_str[2] = '\0';
+}
+
+static void serial_debug_print(const uint8_t *data, uint16_t size, bool write)
+{
+    static bool write_prev = false;
+    uint8_t hex_str[3];
+
+    if(write_prev != write) {
+        write_prev = write;
+        printf("\n--- %s ---\n", write ? "WRITE" : "READ");
+    }
+
+    for(uint32_t i = 0; i < size; i++) {
+        dec_to_hex_str(data[i], hex_str);
+        printf("%s ", hex_str);
+    }
+}
+
+#else
+
+static void serial_debug_print(const uint8_t *data, uint16_t size, bool write) { }
+
+#endif
+
+static uint32_t s_time_end;
+
+esp_loader_error_t loader_port_serial_write(const uint8_t *data, uint16_t size, uint32_t timeout)
+{
+    serial_debug_print(data, size, true);
+
+    HAL_StatusTypeDef err = HAL_UART_Transmit(uart, (uint8_t *)data, size, timeout);
+
+    if (err == HAL_OK) {
+        return ESP_LOADER_SUCCESS;
+    } else if (err == HAL_TIMEOUT) {
+        return ESP_LOADER_ERROR_TIMEOUT;
+    } else {
+        return ESP_LOADER_ERROR_FAIL;
+    }
+}
+
+
+esp_loader_error_t loader_port_serial_read(uint8_t *data, uint16_t size, uint32_t timeout)
+{
+    memset(data, 0x22, size);
+
+    HAL_StatusTypeDef err = HAL_UART_Receive(uart, data, size, timeout);
+
+    serial_debug_print(data, size, false);
+
+    if (err == HAL_OK) {
+        return ESP_LOADER_SUCCESS;
+    } else if (err == HAL_TIMEOUT) {
+        return ESP_LOADER_ERROR_TIMEOUT;
+    } else {
+        return ESP_LOADER_ERROR_FAIL;
+    }
+}
+
+void loader_port_stm32_init(UART_HandleTypeDef *huart, 
+                            GPIO_TypeDef* port_io0, 
+                            uint16_t pin_num_io0,
+                            GPIO_TypeDef* port_rst, 
+                            uint16_t pin_num_rst)
+{
+    uart = huart;
+    gpio_port_io0 = port_io0; 
+    gpio_port_rst = port_rst;
+    gpio_num_io0 = pin_num_io0;
+    gpio_num_rst = pin_num_rst;
+}
+
+// Set GPIO0 LOW, then
+// assert reset pin for 100 milliseconds.
+void loader_port_enter_bootloader(void)
+{
+    HAL_GPIO_WritePin(gpio_port_rst, gpio_num_rst, GPIO_PIN_RESET);
+    HAL_GPIO_WritePin(gpio_port_io0, gpio_num_io0, GPIO_PIN_RESET);
+    HAL_Delay(1);
+    HAL_GPIO_WritePin(gpio_port_rst, gpio_num_rst, GPIO_PIN_SET);
+    HAL_Delay(100);
+    HAL_GPIO_WritePin(gpio_port_io0, gpio_num_io0, GPIO_PIN_SET);
+}
+
+
+void loader_port_reset_target(void)
+{
+    HAL_GPIO_WritePin(gpio_port_rst, gpio_num_rst, GPIO_PIN_RESET);
+    HAL_Delay(100);
+    HAL_GPIO_WritePin(gpio_port_rst, gpio_num_rst, GPIO_PIN_SET);
+}
+
+
+void loader_port_delay_ms(uint32_t ms)
+{
+    HAL_Delay(ms);
+}
+
+
+void loader_port_start_timer(uint32_t ms)
+{
+    s_time_end = HAL_GetTick() + ms;
+}
+
+
+uint32_t loader_port_remaining_time(void)
+{
+    int32_t remaining = s_time_end - HAL_GetTick();
+    return (remaining > 0) ? (uint32_t)remaining : 0;
+}
+
+
+void loader_port_debug_print(const char *str)
+{
+    printf("DEBUG: %s", str);
+}
+
+esp_loader_error_t loader_port_change_baudrate(uint32_t baudrate)
+{
+    uart->Init.BaudRate = baudrate;
+
+    if( HAL_UART_Init(uart) != HAL_OK ) {
+        return ESP_LOADER_ERROR_FAIL;
+    }
+
+    return ESP_LOADER_SUCCESS;
+}

+ 1 - 0
private_include/serial_comm.h

@@ -52,6 +52,7 @@ esp_loader_error_t loader_change_baudrate_cmd(uint32_t baudrate);
 
 esp_loader_error_t loader_md5_cmd(uint32_t address, uint32_t size, uint8_t *md5_out);
 
+esp_loader_error_t loader_spi_parameters(uint32_t total_size);
 
 #ifdef __cplusplus
 }

+ 20 - 2
private_include/serial_comm_prv.h

@@ -17,6 +17,7 @@
 
 #include <stdint.h>
 #include <stdbool.h>
+#include "loader_config.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -78,6 +79,9 @@ typedef struct __attribute__((packed))
     uint32_t packet_count;
     uint32_t packet_size;
     uint32_t offset;
+#ifdef TARGET_ESP32_S2
+    uint32_t encrypted;
+#endif
 } begin_command_t;
 
 typedef struct __attribute__((packed))
@@ -158,8 +162,10 @@ typedef struct __attribute__((packed))
 {
     uint8_t failed;
     uint8_t error;
-    uint8_t reserved_0; // ESP32 ROM only
-    uint8_t reserved_1; // ESP32 ROM only
+#ifndef TARGET_ESP8266
+    uint8_t reserved_0;
+    uint8_t reserved_1;
+#endif
 } response_status_t;
 
 typedef struct __attribute__((packed))
@@ -175,6 +181,18 @@ typedef struct __attribute__((packed))
     response_status_t status;
 } rom_md5_response_t;
 
+typedef struct __attribute__((packed))
+{
+    command_common_t common;
+    uint32_t id;
+    uint32_t total_size;
+    uint32_t block_size;
+    uint32_t sector_size;
+    uint32_t page_size;
+    uint32_t status_mask;
+} write_spi_command_t;  
+
+
 #ifdef __cplusplus
 }
 #endif

+ 224 - 8
src/esp_loader.c

@@ -20,20 +20,89 @@
 #include "esp_loader.h"
 #include "md5_hash.h"
 #include <string.h>
+#include <assert.h>
 
 #ifndef MAX
 #define MAX(a, b) ((a) > (b)) ? (a) : (b)
 #endif
 
+#ifndef MIN
+#define MIN(a, b) ((a) < (b)) ? (a) : (b)
+#endif
+
+typedef struct {
+    uint32_t reg_1;
+    uint32_t reg_2;
+} date_registers_t;
+
+static const date_registers_t date_regs = {
+#if defined TARGET_ESP8266
+    .reg_1 = 0x00062000,
+    .reg_2 = 0
+#elif defined TARGET_ESP32
+    .reg_1 = 0x15122500,
+    .reg_2 = 0
+#elif defined TARGET_ESP32_S2
+    .reg_1 = 0x00000500,
+    .reg_2 = 0x19031400
+#endif
+};
+
+static const uint32_t UART_DATE_REG_ADDR = 0x60000078;    // used to differentiate ESP8266 vs ESP32*
+static const uint32_t UART_DATE_REG2_ADDR = 0x3f400074;   // used to differentiate ESP32-S2 vs other models
+
 static const uint32_t DEFAULT_TIMEOUT = 500;
-static const uint32_t SPI_PIN_CONFIG_DEFAULT = 0;
 static const uint32_t DEFAULT_FLASH_TIMEOUT = 3000;       // timeout for most flash operations
 static const uint32_t ERASE_REGION_TIMEOUT_PER_MB = 3000; // timeout (per megabyte) for erasing a region
 static const uint8_t  PADDING_PATTERN = 0xFF;
 
-
 static uint32_t s_flash_write_size = 0;
 
+#define MEGABYTE  1024 * 1024
+
+size_t size_id_to_flash_size[] = {
+    MEGABYTE / 4,  // 256KB,
+    MEGABYTE / 2,  // 512KB,
+    1 * MEGABYTE,  // 1MB,
+    2 * MEGABYTE,  // 2MB,
+    4 * MEGABYTE,  // 4MB,
+    8 * MEGABYTE,  // 8MB,
+    16 * MEGABYTE  // 16MB
+};
+
+typedef enum {
+    SPI_FLASH_READ_ID = 0x9F
+} spi_flash_cmd_t;
+
+#if defined TARGET_ESP8266
+#define SPI_REG_BASE    0x60000200
+#define SPI_CMD_REG     SPI_REG_BASE + 0x00
+#define SPI_USR_REG     SPI_REG_BASE + 0x1c
+#define SPI_USR1_REG    SPI_REG_BASE + 0x20
+#define SPI_USR2_REG    SPI_REG_BASE + 0x24
+#define SPI_W0_REG      SPI_REG_BASE + 0x40
+#define SPI_MOSI_DLEN_REG 0
+#define SPI_MISO_DLEN_REG 0
+#elif defined TARGET_ESP32_S2
+#define SPI_REG_BASE    0x3f402000
+#define SPI_CMD_REG     SPI_REG_BASE + 0x00
+#define SPI_USR_REG     SPI_REG_BASE + 0x18
+#define SPI_USR1_REG    SPI_REG_BASE + 0x1c
+#define SPI_USR2_REG    SPI_REG_BASE + 0x20
+#define SPI_W0_REG      SPI_REG_BASE + 0x58
+#define SPI_MOSI_DLEN_REG SPI_REG_BASE + 0x24
+#define SPI_MISO_DLEN_REG SPI_REG_BASE + 0x28
+#elif defined TARGET_ESP32
+#define SPI_REG_BASE    0x60002000
+#define SPI_CMD_REG     SPI_REG_BASE + 0x00
+#define SPI_USR_REG     SPI_REG_BASE + 0x1c
+#define SPI_USR1_REG    SPI_REG_BASE + 0x20
+#define SPI_USR2_REG    SPI_REG_BASE + 0x24
+#define SPI_W0_REG      SPI_REG_BASE + 0x80
+#define SPI_MOSI_DLEN_REG SPI_REG_BASE + 0x28
+#define SPI_MISO_DLEN_REG SPI_REG_BASE + 0x2c
+#endif
+
 #if MD5_ENABLED
 
 static const uint32_t MD5_TIMEOUT_PER_MB = 800;
@@ -73,6 +142,19 @@ static uint32_t timeout_per_mb(uint32_t size_bytes, uint32_t time_per_mb)
     return MAX(timeout, DEFAULT_FLASH_TIMEOUT);
 }
 
+static esp_loader_error_t detect_chip(void)
+{
+    uint32_t reg_1, reg_2;
+
+    RETURN_ON_ERROR( esp_loader_read_register(UART_DATE_REG_ADDR,  &reg_1) );
+    RETURN_ON_ERROR( esp_loader_read_register(UART_DATE_REG2_ADDR, &reg_2) );
+
+    if (date_regs.reg_1 == reg_1 && (date_regs.reg_2 == 0 || date_regs.reg_2 == reg_2)) {
+        return ESP_LOADER_SUCCESS;
+    } else {
+        return ESP_LOADER_ERROR_INVALID_TARGET;
+    }
+}
 
 esp_loader_error_t esp_loader_connect(esp_loader_connect_args_t *connect_args)
 {
@@ -94,8 +176,130 @@ esp_loader_error_t esp_loader_connect(esp_loader_connect_args_t *connect_args)
         }
     } while (err != ESP_LOADER_SUCCESS);
 
+    RETURN_ON_ERROR( detect_chip() );
+
+#ifndef TARGET_ESP8266
+    uint32_t SPI_PIN_CONFIG_DEFAULT = 0;
     loader_port_start_timer(DEFAULT_TIMEOUT);
-    return loader_spi_attach_cmd(SPI_PIN_CONFIG_DEFAULT);
+    err = loader_spi_attach_cmd(SPI_PIN_CONFIG_DEFAULT);
+#endif
+
+    return err;
+}
+
+#ifndef TARGET_ESP8266
+
+static esp_loader_error_t spi_set_data_lengths(size_t mosi_bits, size_t miso_bits)
+{
+    if (mosi_bits > 0) {
+        RETURN_ON_ERROR( esp_loader_write_register(SPI_MOSI_DLEN_REG, mosi_bits - 1) );
+    }
+    if (miso_bits > 0) {
+        RETURN_ON_ERROR( esp_loader_write_register(SPI_MISO_DLEN_REG, miso_bits - 1) );
+    }
+
+    return ESP_LOADER_SUCCESS;
+}
+
+#else
+
+static esp_loader_error_t spi_set_data_lengths(size_t mosi_bits, size_t miso_bits)
+{
+    uint32_t mosi_bitlen_shift = 17;
+    uint32_t miso_bitlen_shift = 8;
+    uint32_t mosi_mask = (mosi_bits == 0) ? 0 : mosi_bits - 1;
+    uint32_t miso_mask = (miso_bits == 0) ? 0 : miso_bits - 1;
+    uint32_t usr_reg = (miso_mask << miso_bitlen_shift) | (mosi_mask << mosi_bitlen_shift);
+
+    return esp_loader_write_register(SPI_USR1_REG, usr_reg);
+}
+
+#endif
+
+static esp_loader_error_t spi_flash_command(spi_flash_cmd_t cmd, void *data_tx, size_t tx_size, void *data_rx, size_t rx_size)
+{
+    assert(rx_size <= 32); // Reading more than 32 bits back from a SPI flash operation is unsupported
+    assert(tx_size <= 64); // Writing more than 64 bytes of data with one SPI command is unsupported
+
+    uint32_t SPI_USR_CMD  = (1 << 31);
+    uint32_t SPI_USR_MISO = (1 << 28);
+    uint32_t SPI_USR_MOSI = (1 << 27);
+    uint32_t SPI_CMD_USR  = (1 << 18);
+    uint32_t CMD_LEN_SHIFT = 28;
+
+    // Save SPI configuration
+    uint32_t old_spi_usr;
+    uint32_t old_spi_usr2;
+    RETURN_ON_ERROR( esp_loader_read_register(SPI_USR_REG, &old_spi_usr) );
+    RETURN_ON_ERROR( esp_loader_read_register(SPI_USR2_REG, &old_spi_usr2) );
+
+    RETURN_ON_ERROR( spi_set_data_lengths(tx_size, rx_size) );
+
+    uint32_t usr_reg_2 = (7 << CMD_LEN_SHIFT) | cmd;
+    uint32_t usr_reg = SPI_USR_CMD;
+    if (rx_size > 0) {
+        usr_reg |= SPI_USR_MISO;
+    }
+    if (tx_size > 0) {
+        usr_reg |= SPI_USR_MOSI;
+    }
+
+    RETURN_ON_ERROR( esp_loader_write_register(SPI_USR_REG, usr_reg) );
+    RETURN_ON_ERROR( esp_loader_write_register(SPI_USR2_REG, usr_reg_2 ) );
+
+    if (tx_size == 0) {
+        // clear data register before we read it
+        RETURN_ON_ERROR( esp_loader_write_register(SPI_W0_REG, 0) );
+    } else {
+        uint32_t *data = (uint32_t *)data_tx;
+        uint32_t words_to_write = MIN((tx_size + 31) / 8 * 4, 1);
+        uint32_t data_reg_addr = SPI_W0_REG;
+
+        while (words_to_write--) {
+            uint32_t word = *data++;
+            RETURN_ON_ERROR( esp_loader_write_register(data_reg_addr, word) );
+            data_reg_addr += 4;
+        }
+    }
+
+    RETURN_ON_ERROR( esp_loader_write_register(SPI_CMD_REG, SPI_CMD_USR) );
+
+    uint32_t trials = 10;
+    while (trials--) {
+        uint32_t cmd_reg;
+        RETURN_ON_ERROR( esp_loader_read_register(SPI_CMD_REG, &cmd_reg) );
+        if ((cmd_reg & SPI_CMD_USR) == 0) {
+            break;
+        }
+    }
+
+    if (trials == 0) {
+        return ESP_LOADER_ERROR_TIMEOUT;
+    }
+
+    RETURN_ON_ERROR( esp_loader_read_register(SPI_W0_REG, data_rx) );
+
+    // Restore SPI configuration
+    RETURN_ON_ERROR( esp_loader_write_register(SPI_USR_REG, old_spi_usr) );
+    RETURN_ON_ERROR( esp_loader_write_register(SPI_USR2_REG, old_spi_usr2) );
+
+    return ESP_LOADER_SUCCESS;
+}
+
+static esp_loader_error_t detect_flash_size(size_t *flash_size)
+{
+    uint32_t flash_id = 0;
+
+    RETURN_ON_ERROR( spi_flash_command(SPI_FLASH_READ_ID, NULL, 0, &flash_id, 24) );
+    uint32_t size_id = flash_id >> 16;
+
+    if (size_id < 0x12 && size_id > 0x18) {
+        return ESP_LOADER_ERROR_UNSUPPORTED_CHIP;
+    }
+
+    *flash_size = size_id_to_flash_size[size_id - 0x12];
+
+    return ESP_LOADER_SUCCESS;
 }
 
 
@@ -104,11 +308,21 @@ esp_loader_error_t esp_loader_flash_start(uint32_t offset, uint32_t image_size,
     uint32_t blocks_to_write = (image_size + block_size - 1) / block_size;
     uint32_t erase_size = block_size * blocks_to_write;
     s_flash_write_size = block_size;
+    size_t flash_size;
+
+    if (detect_flash_size(&flash_size) == ESP_LOADER_SUCCESS) {
+        if (image_size > flash_size) {
+            return ESP_LOADER_ERROR_IMAGE_SIZE;
+        }
+        loader_port_start_timer(DEFAULT_TIMEOUT);
+        RETURN_ON_ERROR( loader_spi_parameters(flash_size) );
+    } else {
+        loader_port_debug_print("Flash size detection failed, falling back to default");
+    }
 
     init_md5(offset, image_size);
 
     loader_port_start_timer(timeout_per_mb(erase_size, ERASE_REGION_TIMEOUT_PER_MB));
-
     return loader_flash_begin_cmd(offset, erase_size, block_size, blocks_to_write);
 }
 
@@ -154,12 +368,14 @@ esp_loader_error_t esp_loader_write_register(uint32_t address, uint32_t reg_valu
     return loader_write_reg_cmd(address, reg_value, 0xFFFFFFFF, 0);
 }
 
+#ifndef TARGET_ESP8266
 esp_loader_error_t esp_loader_change_baudrate(uint32_t baudrate)
 {
     loader_port_start_timer(DEFAULT_TIMEOUT);
 
     return loader_change_baudrate_cmd(baudrate);
 }
+#endif
 
 #if MD5_ENABLED
 
@@ -195,16 +411,16 @@ esp_loader_error_t esp_loader_flash_verify(void)
     RETURN_ON_ERROR( loader_md5_cmd(s_start_address, s_image_size, received_md5) );
 
     bool md5_match = memcmp(hex_md5, received_md5, MD5_SIZE) == 0;
-    
-    if(!md5_match) {
+
+    if (!md5_match) {
         hex_md5[MD5_SIZE] = '\n';
         received_md5[MD5_SIZE] = '\n';
 
         loader_port_debug_print("Error: MD5 checksum does not match:\n");
         loader_port_debug_print("Expected:\n");
-        loader_port_debug_print((char*)received_md5);
+        loader_port_debug_print((char *)received_md5);
         loader_port_debug_print("Actual:\n");
-        loader_port_debug_print((char*)hex_md5);
+        loader_port_debug_print((char *)hex_md5);
 
         return ESP_LOADER_ERROR_INVALID_MD5;
     }

+ 30 - 11
src/serial_comm.c

@@ -20,6 +20,7 @@
 #include <string.h>
 // #include <stdio.h>
 
+#define CMD_SIZE(cmd) ( sizeof(cmd) - sizeof(command_common_t) )
 
 static uint32_t s_sequence_number = 0;
 
@@ -243,7 +244,7 @@ esp_loader_error_t loader_flash_begin_cmd(uint32_t offset,
         .common = {
             .direction = WRITE_DIRECTION,
             .command = FLASH_BEGIN,
-            .size = 16,
+            .size = CMD_SIZE(begin_cmd),
             .checksum = 0
         },
         .erase_size = erase_size,
@@ -264,13 +265,11 @@ esp_loader_error_t loader_flash_data_cmd(const uint8_t *data, uint32_t size)
         .common = {
             .direction = WRITE_DIRECTION,
             .command = FLASH_DATA,
-            .size = 16,
+            .size = CMD_SIZE(data_cmd) + size,
             .checksum = compute_checksum(data, size)
         },
         .data_size = size,
         .sequence_number = s_sequence_number++,
-        .zero_0 = 0,
-        .zero_1 = 0
     };
 
     return send_cmd_with_data(&data_cmd, sizeof(data_cmd), data, size);
@@ -283,7 +282,7 @@ esp_loader_error_t loader_flash_end_cmd(bool stay_in_loader)
         .common = {
             .direction = WRITE_DIRECTION,
             .command = FLASH_END,
-            .size = 4,
+            .size = CMD_SIZE(end_cmd),
             .checksum = 0
         },
         .stay_in_loader = stay_in_loader
@@ -299,7 +298,7 @@ esp_loader_error_t loader_sync_cmd(void)
         .common = {
             .direction = WRITE_DIRECTION,
             .command = SYNC,
-            .size = 36,
+            .size = CMD_SIZE(sync_cmd),
             .checksum = 0
         },
         .sync_sequence = {
@@ -322,7 +321,7 @@ esp_loader_error_t loader_write_reg_cmd(uint32_t address, uint32_t value,
         .common = {
             .direction = WRITE_DIRECTION,
             .command = WRITE_REG,
-            .size = 16,
+            .size = CMD_SIZE(write_cmd),
             .checksum = 0
         },
         .address = address,
@@ -341,7 +340,7 @@ esp_loader_error_t loader_read_reg_cmd(uint32_t address, uint32_t *reg)
         .common = {
             .direction = WRITE_DIRECTION,
             .command = READ_REG,
-            .size = 16,
+            .size = CMD_SIZE(read_cmd),
             .checksum = 0
         },
         .address = address,
@@ -357,7 +356,7 @@ esp_loader_error_t loader_spi_attach_cmd(uint32_t config)
         .common = {
             .direction = WRITE_DIRECTION,
             .command = SPI_ATTACH,
-            .size = 8,
+            .size = CMD_SIZE(attach_cmd),
             .checksum = 0
         },
         .configuration = config,
@@ -373,7 +372,7 @@ esp_loader_error_t loader_change_baudrate_cmd(uint32_t baudrate)
         .common = {
             .direction = WRITE_DIRECTION,
             .command = CHANGE_BAUDRATE,
-            .size = 8,
+            .size = CMD_SIZE(baudrate_cmd),
             .checksum = 0
         },
         .new_baudrate = baudrate,
@@ -389,7 +388,7 @@ esp_loader_error_t loader_md5_cmd(uint32_t address, uint32_t size, uint8_t *md5_
         .common = {
             .direction = WRITE_DIRECTION,
             .command = SPI_FLASH_MD5,
-            .size = 16,
+            .size = CMD_SIZE(md5_cmd),
             .checksum = 0
         },
         .address = address,
@@ -401,6 +400,26 @@ esp_loader_error_t loader_md5_cmd(uint32_t address, uint32_t size, uint8_t *md5_
     return send_cmd_md5(&md5_cmd, sizeof(md5_cmd), md5_out);
 }
 
+esp_loader_error_t loader_spi_parameters(uint32_t total_size)
+{
+    write_spi_command_t spi_cmd = {
+        .common = {
+            .direction = WRITE_DIRECTION,
+            .command = SPI_SET_PARAMS,
+            .size = 24,
+            .checksum = 0
+        },
+        .id = 0,
+        .total_size = total_size,
+        .block_size = 64 * 1024,
+        .sector_size = 4 * 1024,
+        .page_size = 0x100,
+        .status_mask = 0xFFFF,
+    };
+
+    return send_cmd(&spi_cmd, sizeof(spi_cmd), NULL);
+}
+
 __attribute__ ((weak)) void loader_port_debug_print(const char *str)
 {
 

+ 20 - 0
submodules/CMakeLists.txt

@@ -0,0 +1,20 @@
+
+cmake_minimum_required(VERSION 3.13)
+
+set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/stm32-cmake/cmake/gcc_stm32.cmake)
+set(CMAKE_MODULE_PATH    ${CMAKE_CURRENT_LIST_DIR}/stm32-cmake/cmake)
+
+find_package(CMSIS REQUIRED)
+find_package(STM32HAL COMPONENTS gpio tim uart REQUIRED)
+
+add_library(stm_cube_impl ${CMSIS_SOURCES} ${STM32HAL_SOURCES})
+target_include_directories(stm_cube_impl PUBLIC ${CMSIS_INCLUDE_DIRS} ${STM32HAL_INCLUDE_DIR})
+stm32_set_target_properties(stm_cube_impl)
+
+# stm_cube target is made to propagate properties of stm_cube_impl, as stm32_set_target_properties 
+# sets properties privately for given target. This eliminates need to call stm32_set_target_properties
+# on every target that links against STM32HAL.
+add_library(stm_cube INTERFACE)
+target_link_libraries(stm_cube INTERFACE stm_cube_impl)
+target_compile_definitions(stm_cube INTERFACE $<TARGET_PROPERTY:stm_cube_impl,COMPILE_DEFINITIONS>)
+target_link_options(stm_cube INTERFACE -T${CMAKE_CURRENT_BINARY_DIR}/stm_cube_impl_flash.ld)

+ 1 - 0
submodules/stm32-cmake

@@ -0,0 +1 @@
+Subproject commit 5f199454c0f51372b339e80aa406b9172b9861c4

+ 8 - 16
test/CMakeLists.txt

@@ -1,24 +1,16 @@
 cmake_minimum_required(VERSION 3.5)
 project(serial_flasher_test)
 
-set( CMAKE_CXX_FLAGS "-Wall -Werror -O3 -std=c++14" )
+add_executable( ${PROJECT_NAME} test_main.cpp ../src/serial_comm.c ../src/esp_loader.c ../src/md5_hash.c )
 
-include_directories( ../include ../private_include ../test )
+target_include_directories(${PROJECT_NAME} PRIVATE ../include ../private_include ../test)
 
-set( TEST_SOURCES
-  test_main.cpp 
-  ../src/serial_comm.c
-  ../src/esp_loader.c
-  ../src/md5_hash.c
-)
+target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Werror -O3)
 
-# Set -DQEMU_TEST=True to run qemu tests. Host tests are run otherwise.
-if( QEMU_TEST ) 
-    message("Qemu test ")
-    set(TEST_SOURCES ${TEST_SOURCES} serial_io_tcp.cpp qemu_test.cpp)
+set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14)
+
+if( QEMU_TEST )
+    target_sources(${PROJECT_NAME} PRIVATE serial_io_tcp.cpp qemu_test.cpp)
 else()
-    message("Host test")
-    set(TEST_SOURCES ${TEST_SOURCES} serial_io_mock.cpp test.cpp )
+    target_sources(${PROJECT_NAME} PRIVATE serial_io_mock.cpp test.cpp)
 endif()
-
-add_executable( ${PROJECT_NAME} ${TEST_SOURCES} )

+ 1 - 0
test/loader_config_user.h

@@ -0,0 +1 @@
+#pragma once

+ 6 - 1
test/serial_io_mock.cpp

@@ -129,6 +129,11 @@ int8_t *write_buffer_data()
     return write_buffer.data();
 }
 
+size_t write_buffer_size()
+{
+    return write_buffer.size();
+}
+
 void set_read_buffer(const void *data, size_t size)
 {
     SLIP_encode((const int8_t *)data, size, read_buffer);
@@ -137,7 +142,7 @@ void set_read_buffer(const void *data, size_t size)
 void print_array(int8_t *data, uint32_t size)
 {
     for (uint32_t i = 0; i < size; i++) {
-        printf("%0x, ", (uint8_t)data[i]);
+        printf("%02x, ", (uint8_t)data[i]);
     }
     printf("\n");
 }

+ 1 - 0
test/serial_io_mock.h

@@ -21,6 +21,7 @@
 void clear_buffers();
 
 void write_buffer_print();
+size_t write_buffer_size();
 int8_t* write_buffer_data();
 
 void set_read_buffer(const void *data, size_t size);

+ 56 - 6
test/test.cpp

@@ -73,6 +73,7 @@ inline void queue_response(expected_response &response, size_t size = sizeof(exp
     set_read_buffer(&response, size);
 }
 
+expected_response set_params_response(SPI_SET_PARAMS);
 expected_response flash_begin_response(FLASH_BEGIN);
 expected_response flash_data_response(FLASH_DATA);
 expected_response flash_end_response(FLASH_END);
@@ -83,6 +84,24 @@ expected_response sync_response(SYNC);
 
 
 struct __attribute__((packed)) flash_start_frame {
+    
+    uint8_t delimiter_1 = 0xc0;
+    write_spi_command_t write_spi_command = {
+        .common = {
+            .direction = WRITE_DIRECTION,
+            .command = SPI_SET_PARAMS,
+            .size = 24,
+            .checksum = 0
+        },
+        .id = 0,
+        .total_size = 0x00400000, // Assume 4MB flash size
+        .block_size = 64 * 1024,
+        .sector_size = 4 * 1024,
+        .page_size = 0x100,
+        .status_mask = 0xFFFF,
+    };
+    uint8_t delimiter_2 = 0xc0;
+
     uint8_t delimiter_3 = 0xc0;
     begin_command_t begin_cmd  = {
         .common = {
@@ -132,7 +151,7 @@ struct __attribute__((packed)) flash_write_frame {
         .common = {
             .direction = WRITE_DIRECTION,
             .command = FLASH_DATA,
-            .size = 16,
+            .size = 16 + PAYLOAD_SIZE,
             .checksum = 0xef,
         },
         .data_size = PAYLOAD_SIZE,
@@ -188,6 +207,28 @@ template<size_t PAYLOAD_SIZE>
 uint32_t flash_write_frame<PAYLOAD_SIZE>::seq_num = 0;
 
 
+size_t queue_responses_to_ignore()
+{
+    auto flash_id_response = read_reg_response;
+    flash_id_response.data.common.value = 0x16 << 16; // emulate 4MB flash
+
+    queue_response(read_reg_response);  // Save SPI_USR_REG 
+    queue_response(read_reg_response);  // Save SPI_USR2_REG
+    queue_response(write_reg_response); // SPI_MISO_DLEN_REG
+    queue_response(write_reg_response); // Set new SPI_USR_REG
+    queue_response(write_reg_response); // Set new SPI_USR2_REG
+    queue_response(write_reg_response); // Zero out SPI_W0_REG
+    queue_response(write_reg_response); // SPI_CMD_REG Start transaction
+    queue_response(read_reg_response);  // SPI_CMD_REG Transaction done
+    queue_response(flash_id_response);  // SPI_W0_REG Read data
+    queue_response(write_reg_response); // Restore SPI_USR_REG
+    queue_response(write_reg_response); // Restore SPI_USR2_REG
+ 
+    // Delimiters are added manually to every packet (+2).
+    size_t bytes_to_ignore = (sizeof(write_reg_command_t) + 2) * 7 + (sizeof(read_reg_command_t) + 2) * 4 ;
+
+    return bytes_to_ignore;
+}
 
 TEST_CASE( "Large payload that does not fit BLOCK_SIZE is split into \
             multiple data frames. Last data frame is padded with 0xFF" )
@@ -206,11 +247,14 @@ TEST_CASE( "Large payload that does not fit BLOCK_SIZE is split into \
 
     // Check flash start operation 
     clear_buffers();
+    size_t bytes_to_ignore = queue_responses_to_ignore();
+
+    queue_response(set_params_response);
     queue_response(flash_begin_response);
 
     REQUIRE ( esp_loader_flash_start(0, sizeof(data) * 3, BLOCK_SIZE) == ESP_LOADER_SUCCESS );
-    
-    REQUIRE( memcmp(write_buffer_data(), &expected_start, sizeof(expected_start)) == 0 );
+    // Ignore read/write register commands in this test.
+    REQUIRE( memcmp(write_buffer_data() + bytes_to_ignore, &expected_start, sizeof(expected_start)) == 0 );
 
 
     // Check flash write operation 
@@ -224,15 +268,21 @@ TEST_CASE( "Large payload that does not fit BLOCK_SIZE is split into \
     REQUIRE( esp_loader_flash_write(data, 200) == ESP_LOADER_SUCCESS );
 
     REQUIRE( memcmp(write_buffer_data(), &expected_data, sizeof(expected_data)) == 0 );
-
-    // queue_response(flash_end_response);
 }
 
 
 TEST_CASE( "Can connect within specified time " )
 {
+    // Set date registers used for detection of attached chip
+    auto uart_date_reg_1 = read_reg_response;
+    auto uart_date_reg_2 = read_reg_response;
+    uart_date_reg_1.data.common.value = 0x15122500;
+    uart_date_reg_2.data.common.value = 0;
+
     clear_buffers();
     queue_response(sync_response);
+    queue_response(uart_date_reg_1);
+    queue_response(uart_date_reg_2);
     queue_response(attach_response);
 
     esp_loader_connect_args_t connect_config = {
@@ -301,7 +351,7 @@ TEST_CASE ( "SLIP is encoded correctly" )
         0xc0,       // Begin
         0x00,         // Write direction
         0x03,         // FLASH_DATA command
-        16, 0,        // Number of characters to send
+        16 + sizeof(data), 0, // Number of characters to send
         0x33, 0, 0, 0,// Checksum
         sizeof(data), 0, 0, 0, // Data size
         0, 0, 0, 0,   // Sequence number