Browse Source

Merge branch 'ci/zephyr' into 'master'

zephyr: add initial support

Closes ESF-26 and ESF-21

See merge request espressif/esp-serial-flasher!49
Roland Dobai 2 năm trước cách đây
mục cha
commit
ea94c008f7

+ 34 - 0
.gitlab-ci.yml

@@ -15,6 +15,10 @@ variables:
   STM32_CUBE_F4_REPO_TAG: v1.26.2
   ARM_TOOLCHAIN_URL: 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
   QEMU_PATH: /opt/qemu/bin/qemu-system-xtensa
+  ZEPHYR_REPO: https://github.com/zephyrproject-rtos/zephyr.git
+  ZEPHYR_REPO_REV: v3.2.0
+  ZEPHYR_TOOLCHAIN: https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.15.2/toolchain_linux-x86_64_xtensa-espressif_esp32_zephyr-elf.tar.gz
+  ZEPHYR_SDK: https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.15.2/zephyr-sdk-0.15.2_linux-aarch64_minimal.tar.gz
 
 .build_idf_template:
   stage: build
@@ -75,6 +79,36 @@ build_stm32:
     - cmake -DTOOLCHAIN_PREFIX=$CI_PROJECT_DIR/gcc-arm-none-eabi -DSTM32Cube_DIR=$CI_PROJECT_DIR/STM32CubeF4 -G Ninja ..
     - cmake --build .
 
+build_zephyr:
+  stage: build
+  image: espressif/idf:latest
+  tags:
+    - build
+    - internet
+  script:
+    - mkdir $CI_PROJECT_DIR/zephyrproject-rtos
+    - cd $CI_PROJECT_DIR/zephyrproject-rtos
+    - git clone --single-branch --depth=1 -b ${ZEPHYR_REPO_REV} ${ZEPHYR_REPO}
+    - mkdir $CI_PROJECT_DIR/zephyrproject-rtos/zephyr-sdk
+    - cd $CI_PROJECT_DIR/zephyrproject-rtos/zephyr-sdk
+    - wget --no-verbose -O zephyr_sdk.tar.gz ${ZEPHYR_SDK}
+    - tar xvf zephyr_sdk.tar.gz --strip-components=1
+    - wget --no-verbose -O esp32_toolchain.tar.gz ${ZEPHYR_TOOLCHAIN}
+    - tar xvf esp32_toolchain.tar.gz
+    - export ZEPHYR_SDK_INSTALL_DIR=$(pwd)
+    - export ZEPHYR_TOOLCHAIN_VARIANT="zephyr"
+    - cd $CI_PROJECT_DIR/zephyrproject-rtos/zephyr
+    - export ZEPHYR_BASE=$(pwd)
+    - pip install -r scripts/requirements.txt
+    - pip install wheel
+    - if [[ ! -d "$CI_PROJECT_DIR/zephyrproject-rtos/.west" ]]; then
+    - west init -l .
+    - fi
+    - unset IDF_PATH
+    - west zephyr-export
+    - west update hal_espressif
+    - west build -p -b esp32 $CI_PROJECT_DIR/examples/zephyr_example -DZEPHYR_EXTRA_MODULES=$CI_PROJECT_DIR
+
 run_tests:
   stage: test
   image: ${CI_DOCKER_REGISTRY}/qemu:esp-develop-20191124

+ 25 - 1
README.md

@@ -9,6 +9,7 @@ Supported **host** microcontrollers:
 - STM32
 - Raspberry Pi
 - ESP32
+- MCU running Zephyr OS
 
 Supported **target** microcontrollers:
 
@@ -38,7 +39,7 @@ 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 ports for [ESP32 port](port/esp32_port.c) and [STM32 port](port/stm32_port.c) are available.
+Please refer to ports in `port` directory. Currently, only ports for [ESP32 port](port/esp32_port.c), [STM32 port](port/stm32_port.c), and [Zephyr port](port/zephyr_port.c) are available.
 
 ## Configuration
 
@@ -104,6 +105,29 @@ set(STM32_CHIP          STM32F407VG)
 set(PORT                STM32)
 ```
 
+### Zephyr support
+
+The Zephyr port is ready to be integrated into your Zephyr app as a Zephyr module. In the manifest file (west.yml), add:
+
+```
+    - name: esp-flasher
+      url: https://github.com/espressif/esp-serial-flasher
+      revision: master
+      path: modules/lib/esp_flasher
+```
+
+And add
+
+```
+CONFIG_ESP_SERIAL_FLASHER=y
+CONFIG_CONSOLE_GETCHAR=y
+CONFIG_SERIAL_FLASHER_MD5_ENABLED=y
+```
+
+to your project configuration `prj.conf`.
+
+For your C/C++ source code, you can use the example code provided in `examples/zephyr_example` as a starting point.
+
 ## Licence
 
 Code is distributed under Apache 2.0 license.

+ 24 - 0
examples/zephyr_example/CMakeLists.txt

@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: Apache-2.0
+
+cmake_minimum_required(VERSION 3.20.0)
+
+find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
+project(zephyr_flasher)
+
+zephyr_compile_definitions_ifdef(CONFIG_SERIAL_FLASHER_MD5_ENABLED MD5_ENABLED)
+
+zephyr_library_sources(
+  ../common/example_common.c
+  )
+
+zephyr_library_include_directories(
+  ../common
+  ../binaries
+  )
+
+# Embed binaries into the app.
+include(${CMAKE_CURRENT_LIST_DIR}/../common/bin2array.cmake)
+create_resources(${CMAKE_CURRENT_LIST_DIR}/../binaries/Hello-world ${CMAKE_BINARY_DIR}/binaries.c)
+set_property(SOURCE ${CMAKE_BINARY_DIR}/binaries.c PROPERTY GENERATED 1)
+
+target_sources(app PRIVATE src/main.c  ${CMAKE_BINARY_DIR}/binaries.c)

+ 84 - 0
examples/zephyr_example/README.md

@@ -0,0 +1,84 @@
+# ESP32 Zephyr example
+
+## Overview
+
+This sample code 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.
+Binaries to be flashed from host MCU to another Espressif SoC can be found in `binaries` folder
+and are converted into C-array during build process.
+
+Following steps are performed in order to re-program target's memory:
+
+1. Peripherals are initialized (GPIO for BOOT and EN pins and UART).
+2. UART1 (can be changed) 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) |
+|:------------:|:-------------:|
+|    IO4       |      IO0      |
+|    IO2       |     RESET     |
+|    IO9       |      TX0      |
+|    IO10      |      RX0      |
+
+Note: interconnection is the same for all three targets (slaves).
+
+## Build and flash
+
+To run the example, type the following command:
+
+```c
+west build -p -b esp32
+west flash
+west espressif monitor
+```
+
+(To exit the serial monitor, type ``ctrl-c``.)
+
+For more information, check [Zephyr's Getting Started](https://docs.zephyrproject.org/latest/develop/getting_started/index.html)
+
+## Configuration
+
+For details about available configuration option, please refer to top level [README.md](../../README.md).
+Compile definitions can be specified in `prj.conf` file.
+
+Binaries to be flashed are placed in separate folder (binaries.c) for each possible target and converted to C-array. Without explicitly enabling MD5 check, flash integrity verification is disabled by default.
+
+## Example output
+
+Here is the example's console output:
+
+```
+*** Booting Zephyr OS build zephyr-v3.2.0-3548-ga1bb9c9d1736 ***
+Running ESP Flasher from Zephyr
+Connected to target
+Baudrate changed
+Erasing flash (this may take a while)...
+Start programming
+Progress: 100 %
+Finished programming
+Erasing flash (this may take a while)...
+Start programming
+Progress: 100 %
+Finished programming
+Erasing flash (this may take a while)...
+Start programming
+Progress: 100 %
+Finished programming
+```

+ 34 - 0
examples/zephyr_example/boards/esp32.overlay

@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/dt-bindings/pinctrl/esp-pinctrl-common.h>
+#include <dt-bindings/pinctrl/esp32-pinctrl.h>
+#include <zephyr/dt-bindings/pinctrl/esp32-gpio-sigmap.h>
+
+/ {
+	aliases {
+		en = &en_button;
+		boot = &boot_button;
+		uart1 = &uart1;
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		en_button: en_button {
+			gpios = <&gpio0 2 (GPIO_PULL_UP | GPIO_ACTIVE_HIGH)>;
+		};
+		boot_button: boot_button {
+			gpios = <&gpio0 4 (GPIO_PULL_UP | GPIO_ACTIVE_HIGH)>;
+		};
+	};
+};
+
+&uart1 {
+	status = "okay";
+	current-speed = <115200>;
+	pinctrl-0 = <&uart1_default>;
+	pinctrl-names = "default";
+};

+ 4 - 0
examples/zephyr_example/prj.conf

@@ -0,0 +1,4 @@
+# nothing here
+CONFIG_CONSOLE=y
+CONFIG_CONSOLE_GETCHAR=y
+CONFIG_NEWLIB_LIBC=y

+ 7 - 0
examples/zephyr_example/sample.yaml

@@ -0,0 +1,7 @@
+sample:
+  description: ESP Serial Flasher sample code
+  name: zephyr_flasher
+tests:
+  sample.esp_flasher.zephyr_example:
+    platform_allow: esp32
+    tags: esp32

+ 81 - 0
examples/zephyr_example/src/main.c

@@ -0,0 +1,81 @@
+/*
+ * ESP Flasher Library Example for Zephyr
+ * Written in 2022 by KT-Elektronik, Klaucke und Partner GmbH
+ * 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.
+ *
+ * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd.
+ */
+
+#include <zephyr/kernel.h>
+#include <zephyr/device.h>
+#include <zephyr/devicetree.h>
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/sys/util.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <zephyr_port.h>
+#include <esp_loader.h>
+#include "example_common.h"
+
+#define HIGHER_BAUDRATE 230400
+#define DEFAULT_BAUDRATE 115200
+
+/* Get UART DTS entry used as flash interface */
+static const struct device *esp_uart_dev = DEVICE_DT_GET(DT_ALIAS(uart1));
+/* Get GPIO pin connected to the ESP's enable pin. */
+static const struct gpio_dt_spec esp_enable_spec = GPIO_DT_SPEC_GET(DT_ALIAS(en), gpios);
+/* Get GPIO pin  connected to the ESP's boot pin. */
+static const struct gpio_dt_spec esp_boot_spec = GPIO_DT_SPEC_GET(DT_ALIAS(boot), gpios);
+
+void main(void)
+{
+	example_binaries_t bin;
+
+	const loader_zephyr_config_t config = {
+		.uart_dev = esp_uart_dev,
+		.enable_spec = esp_enable_spec,
+		.boot_spec = esp_boot_spec
+	};
+
+	printk("Running ESP Flasher from Zephyr\r\n");
+
+	if (!device_is_ready(esp_uart_dev)) {
+		printk("ESP UART not ready");
+		return;
+	}
+
+	if (!device_is_ready(esp_boot_spec.port)) {
+		printk("ESP boot GPIO not ready");
+		return;
+	}
+
+	if (!device_is_ready(esp_enable_spec.port)) {
+		printk("Bluetooth Enable GPIO not ready");
+		return;
+	}
+
+	gpio_pin_configure_dt(&esp_boot_spec, GPIO_OUTPUT_ACTIVE);
+	gpio_pin_configure_dt(&esp_enable_spec, GPIO_OUTPUT_INACTIVE);
+
+	if (loader_port_zephyr_init(&config) != ESP_LOADER_SUCCESS) {
+		printk("ESP loader init failed");
+		return;
+	}
+
+	if (connect_to_target(HIGHER_BAUDRATE) == ESP_LOADER_SUCCESS) {
+
+		get_example_binaries(esp_loader_get_target(), &bin);
+
+		flash_binary(bin.boot.data, bin.boot.size, bin.boot.addr);
+		flash_binary(bin.part.data, bin.part.size, bin.part.addr);
+		flash_binary(bin.app.data,  bin.app.size,  bin.app.addr);
+	}
+
+	loader_port_change_baudrate(DEFAULT_BAUDRATE);
+
+	loader_port_reset_target();
+}

+ 157 - 0
port/zephyr_port.c

@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2022 KT-Elektronik, Klaucke und Partner GmbH
+ *
+ * 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 "zephyr_port.h"
+#include <zephyr/drivers/uart.h>
+#include <zephyr/console/tty.h>
+
+static const struct device *uart_dev;
+static struct gpio_dt_spec enable_spec;
+static struct gpio_dt_spec boot_spec;
+
+static struct tty_serial tty;
+static char tty_rx_buf[CONFIG_ESP_SERIAL_FLASHER_UART_BUFSIZE];
+static char tty_tx_buf[CONFIG_ESP_SERIAL_FLASHER_UART_BUFSIZE];
+
+esp_loader_error_t configure_tty()
+{
+    if (tty_init(&tty, uart_dev) < 0 ||
+        tty_set_rx_buf(&tty, tty_rx_buf, sizeof(tty_rx_buf)) < 0 ||
+        tty_set_tx_buf(&tty, tty_tx_buf, sizeof(tty_tx_buf)) < 0) {
+        return ESP_LOADER_ERROR_FAIL;
+    }
+
+    return ESP_LOADER_SUCCESS;
+}
+
+esp_loader_error_t loader_port_serial_read(uint8_t *data, const uint16_t size, const uint32_t timeout)
+{
+    ssize_t bytes_read = 0;
+
+    if (!device_is_ready(uart_dev) || data == NULL || size == 0) {
+        return ESP_LOADER_ERROR_FAIL;
+    }
+
+    tty_set_rx_timeout(&tty, timeout);
+    while (bytes_read < size) {
+        uint16_t chunk = CONFIG_ESP_SERIAL_FLASHER_UART_BUFSIZE;
+        if (size < CONFIG_ESP_SERIAL_FLASHER_UART_BUFSIZE) {
+            chunk = size;
+        }
+
+        ssize_t read = tty_read(&tty, &data[bytes_read], chunk);
+        if (read < 0) {
+            return ESP_LOADER_ERROR_TIMEOUT;
+        } else {
+            bytes_read += read;
+        }
+    }
+
+    if (bytes_read != size) return ESP_LOADER_ERROR_FAIL;
+
+    return ESP_LOADER_SUCCESS;
+}
+
+esp_loader_error_t loader_port_serial_write(const uint8_t *data, const uint16_t size, const uint32_t timeout)
+{
+    ssize_t bytes_wrote = 0;
+
+    if (!device_is_ready(uart_dev) || data == NULL || size == 0) {
+        return ESP_LOADER_ERROR_FAIL;
+    }
+
+    tty_set_tx_timeout(&tty, timeout);
+    while (bytes_wrote < size) {
+        uint16_t chunk = CONFIG_ESP_SERIAL_FLASHER_UART_BUFSIZE;
+        if (size < CONFIG_ESP_SERIAL_FLASHER_UART_BUFSIZE) {
+            chunk = size;
+        }
+
+        ssize_t read = tty_write(&tty, &data[bytes_wrote], chunk);
+        if (read < 0) {
+            return ESP_LOADER_ERROR_TIMEOUT;
+        } else {
+            bytes_wrote += read;
+        }
+    }
+
+    if (bytes_wrote != size) return ESP_LOADER_ERROR_FAIL;
+
+    return ESP_LOADER_SUCCESS;
+}
+
+esp_loader_error_t loader_port_zephyr_init(const loader_zephyr_config_t *config)
+{
+    uart_dev = config->uart_dev;
+    enable_spec = config->enable_spec;
+    boot_spec = config->boot_spec;
+    return configure_tty();
+}
+
+void loader_port_reset_target(void)
+{
+    gpio_pin_set_dt(&enable_spec, false);
+    loader_port_delay_ms(CONFIG_SERIAL_FLASHER_RESET_HOLD_TIME_MS);
+    gpio_pin_set_dt(&enable_spec, true);
+}
+
+void loader_port_enter_bootloader(void)
+{
+    gpio_pin_set_dt(&boot_spec, false);
+    loader_port_reset_target();
+    loader_port_delay_ms(CONFIG_SERIAL_FLASHER_BOOT_HOLD_TIME_MS);
+    gpio_pin_set_dt(&boot_spec, true);
+}
+
+void loader_port_delay_ms(uint32_t ms)
+{
+    k_msleep(ms);
+}
+
+static uint64_t s_time_end;
+
+void loader_port_start_timer(uint32_t ms)
+{
+    s_time_end = sys_clock_timeout_end_calc(Z_TIMEOUT_MS(ms));
+}
+
+uint32_t loader_port_remaining_time(void)
+{
+    int64_t remaining = k_ticks_to_ms_floor64(s_time_end - k_uptime_ticks());
+    return (remaining > 0) ? (uint32_t)remaining : 0;
+}
+
+esp_loader_error_t loader_port_change_baudrate(uint32_t baudrate)
+{
+    struct uart_config uart_config;
+
+    if (!device_is_ready(uart_dev)) {
+        return ESP_LOADER_ERROR_FAIL;
+    }
+
+    if (uart_config_get(uart_dev, &uart_config) != 0) {
+        return ESP_LOADER_ERROR_FAIL;
+    }
+    uart_config.baudrate = baudrate;
+
+    if (uart_configure(uart_dev, &uart_config) != 0) {
+        return ESP_LOADER_ERROR_FAIL;
+    }
+
+    /* bitrate-change can require tty re-configuration */
+    return configure_tty();
+}
+

+ 39 - 0
port/zephyr_port.h

@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2022 KT-Elektronik, Klaucke und Partner GmbH
+ *
+ * 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
+
+#include "serial_io.h"
+#include <zephyr/kernel.h>
+#include <zephyr/drivers/gpio.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    const struct device *uart_dev;
+    const struct gpio_dt_spec enable_spec;
+    const struct gpio_dt_spec boot_spec;
+} loader_zephyr_config_t;
+
+esp_loader_error_t loader_port_zephyr_init(const loader_zephyr_config_t *config);
+
+#ifdef __cplusplus
+}
+#endif
+

+ 1 - 1
src/esp_loader.c

@@ -365,4 +365,4 @@ esp_loader_error_t esp_loader_flash_verify(void)
 void esp_loader_reset_target(void)
 {
     loader_port_reset_target();
-}
+}

+ 26 - 0
zephyr/CMakeLists.txt

@@ -0,0 +1,26 @@
+cmake_minimum_required(VERSION 3.5)
+
+if (CONFIG_ESP_SERIAL_FLASHER)
+    zephyr_include_directories(
+        "${ZEPHYR_CURRENT_MODULE_DIR}/include"
+        "${ZEPHYR_CURRENT_MODULE_DIR}/port"
+        "${ZEPHYR_CURRENT_MODULE_DIR}/private_include"
+    )
+
+    zephyr_interface_library_named(esp_flasher)
+
+    zephyr_library()
+
+    zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/src/esp_loader.c
+                ${ZEPHYR_CURRENT_MODULE_DIR}/src/esp_targets.c
+                ${ZEPHYR_CURRENT_MODULE_DIR}/src/serial_comm.c
+                ${ZEPHYR_CURRENT_MODULE_DIR}/src/md5_hash.c
+                ${ZEPHYR_CURRENT_MODULE_DIR}/port/zephyr_port.c
+    )
+
+    zephyr_library_link_libraries(esp_flasher)
+
+    if(DEFINED MD5_ENABLED OR CONFIG_SERIAL_FLASHER_MD5_ENABLED)
+        target_compile_definitions(esp_flasher INTERFACE -DMD5_ENABLED=1)
+    endif()
+endif()

+ 16 - 0
zephyr/Kconfig

@@ -0,0 +1,16 @@
+config ESP_SERIAL_FLASHER
+    bool "Enable ESP serial flasher library"
+    default y
+    select CONSOLE_SUBSYS
+    help
+      Select this option to enable the ESP serial flasher library.
+
+config ESP_SERIAL_FLASHER_UART_BUFSIZE
+    int "ESP Serial Flasher UART buffer size"
+    default 512
+    help
+      Buffer size for UART TX and RX packets
+
+if ESP_SERIAL_FLASHER
+    rsource "../Kconfig"
+endif

+ 5 - 0
zephyr/module.yml

@@ -0,0 +1,5 @@
+name: esp-flasher
+
+build:
+  cmake: zephyr
+  kconfig: zephyr/Kconfig