mdw-octoml commented on a change in pull request #7557:
URL: https://github.com/apache/tvm/pull/7557#discussion_r591794129
##########
File path: apps/microtvm/zephyr/demo_runtime/src/main.c
##########
@@ -22,108 +22,145 @@
* SPDX-License-Identifier: Apache-2.0
*/
+
+/*
+ * This is a sample Zephyr-based application that contains the logic
+ * needed to upload and control a uTVM-based model via the UART.
+ * This is only intended to be a demonstration, since typically you
+ * will want to incorporate this logic into your own application.
+ */
+
+
#include <drivers/gpio.h>
#include <drivers/uart.h>
+#include <fatal.h>
#include <kernel.h>
#include <power/reboot.h>
-#include <random/rand32.h>
#include <stdio.h>
#include <sys/printk.h>
#include <sys/ring_buffer.h>
#include <tvm/runtime/crt/logging.h>
#include <tvm/runtime/crt/utvm_rpc_server.h>
#include <unistd.h>
#include <zephyr.h>
+#include <random/rand32.h>
#ifdef CONFIG_ARCH_POSIX
#include "posix_board_if.h"
#endif
#include "crt_config.h"
-K_SEM_DEFINE(tx_sem, 0, 1);
-
static const struct device* tvm_uart;
-int write_hook(int c) {
- uart_poll_out(tvm_uart, c);
- return 0;
-}
+#ifdef CONFIG_LED
+#define LED0_NODE DT_ALIAS(led0)
+#define LED0 DT_GPIO_LABEL(LED0_NODE, gpios)
+#define LED0_PIN DT_GPIO_PIN(LED0_NODE, gpios)
+#define LED0_FLAGS DT_GPIO_FLAGS(LED0_NODE, gpios)
+static const struct device* led0_pin;
+#endif // CONFIG_LED
+
+static size_t g_num_bytes_requested = 0;
+static size_t g_num_bytes_written = 0;
+// Used by TVM to write serial data to the UART.
ssize_t write_serial(void* unused_context, const uint8_t* data, size_t size) {
+#ifdef CONFIG_LED
+ gpio_pin_set(led0_pin, LED0_PIN, 1);
+#endif
+ g_num_bytes_requested += size;
+
for (size_t i = 0; i < size; i++) {
uart_poll_out(tvm_uart, data[i]);
+ g_num_bytes_written++;
}
+#ifdef CONFIG_LED
+ gpio_pin_set(led0_pin, LED0_PIN, 0);
+#endif
+
return size;
}
-size_t TVMPlatformFormatMessage(char* out_buf, size_t out_buf_size_bytes,
const char* fmt,
- va_list args) {
+// This is an error handler which will be invoked if the device crashes.
+// Here, we turn on the LED and spin.
+void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *esf) {
+#ifdef CONFIG_LED
+ gpio_pin_set(led0_pin, LED0_PIN, 1);
+#endif
+ for (;;) ;
+}
+
+// Used by TVM when a message needs to be formatted.
+size_t TVMPlatformFormatMessage(char* out_buf, size_t out_buf_size_bytes,
+ const char* fmt, va_list args) {
return vsnprintk(out_buf, out_buf_size_bytes, fmt, args);
}
+// Used by TVM when an abort operation occurs.
void TVMPlatformAbort(tvm_crt_error_t error) {
sys_reboot(SYS_REBOOT_COLD);
- for (;;)
- ;
+#ifdef CONFIG_LED
+ gpio_pin_set(led0_pin, LED0_PIN, 1);
+#endif
+ for (;;) ;
}
-K_MEM_POOL_DEFINE(tvm_memory_pool, 64, 1024, 120, 4);
+// Used by TVM to generate random data.
+tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t* buffer, size_t num_bytes) {
+ uint32_t random; // one unit of random data.
-tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes, DLContext ctx,
void** out_ptr) {
- *out_ptr = k_mem_pool_malloc(&tvm_memory_pool, num_bytes);
- return (*out_ptr == NULL) ? kTvmErrorPlatformNoMemory : kTvmErrorNoError;
-}
+ // Fill parts of `buffer` which are as large as `random`.
+ size_t num_full_blocks = num_bytes / sizeof(random);
+ for (int i = 0; i < num_full_blocks; ++i) {
+ random = sys_rand32_get();
+ memcpy(&buffer[i * sizeof(random)], &random, sizeof(random));
+ }
+
+ // Fill any leftover tail which is smaller than `random`.
+ size_t num_tail_bytes = num_bytes % sizeof(random);
+ if (num_tail_bytes > 0) {
+ random = sys_rand32_get();
+ memcpy(&buffer[num_bytes - num_tail_bytes], &random, num_tail_bytes);
+ }
-tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLContext ctx) {
- k_free(ptr);
return kTvmErrorNoError;
}
-uint32_t g_utvm_start_time;
-
#define MILLIS_TIL_EXPIRY 200
#define TIME_TIL_EXPIRY (K_MSEC(MILLIS_TIL_EXPIRY))
K_TIMER_DEFINE(g_utvm_timer, /* expiry func */ NULL, /* stop func */ NULL);
+uint32_t g_utvm_start_time;
int g_utvm_timer_running = 0;
-#ifdef CONFIG_LED
-/* The devicetree node identifier for the "led0" alias. */
-#define LED0_NODE DT_ALIAS(led0)
-
-#define LED0 DT_GPIO_LABEL(LED0_NODE, gpios)
-#define PIN DT_GPIO_PIN(LED0_NODE, gpios)
-#define FLAGS DT_GPIO_FLAGS(LED0_NODE, gpios)
-
-static struct device* led_pin;
-#endif // CONFIG_LED
-
+// Used to start system timer.
tvm_crt_error_t TVMPlatformTimerStart() {
if (g_utvm_timer_running) {
TVMLogf("timer already running");
- return kTvmErrorPlatformTimerBadState;
+ return kTvmErrorSystemErrorMask | 1;
Review comment:
I just reverted this change to use that existing error code.
##########
File path: tutorials/micro/micro_onnx.py
##########
@@ -0,0 +1,209 @@
+#!/usr/bin/env python3
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+"""
+microTVM with ONNX models
+=========================
+**Author**: `Matt Welsh <https://www.mdw.la/>`
+
+This tutorial is an introduction to compiling and
+running an ONNX model on a device using microTVM.
+"""
+
+# Setup
+# -----
+#
+# Build TVM wth ``USE_MICRO``
Review comment:
Added a link to that.
##########
File path: tutorials/micro/micro_onnx.py
##########
@@ -0,0 +1,209 @@
+#!/usr/bin/env python3
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+"""
+microTVM with ONNX models
+=========================
+**Author**: `Matt Welsh <https://www.mdw.la/>`
+
+This tutorial is an introduction to compiling and
+running an ONNX model on a device using microTVM.
+"""
+
+# Setup
+# -----
+#
+# Build TVM wth ``USE_MICRO``
+# ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+#
+# Download the TVM sources, and build TVM from source following the
+# instructions `on this page
+# <https://tvm.apache.org/docs/install/from_source.html#install-from-source>`.
+# When bulding TVM, ensure that the following lines are present in
+# your ``config.cmake`` file:
+# .. code-block:: bash
+#
+# # Whether enable MicroTVM runtime
+# set(USE_MICRO ON)
+#
+# Install Python dependencies
+# ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+#
+# microTVM and this tutorial require a number of Python dependencies --
+# in addition to TVM itself -- to be installed in your Python environment.
+# For convenience, we have provided a `Poetry <https://python-poetry.org/>`
+# ``pyproject.toml`` configuration file in the directory ``apps/microtvm``.
+# You can use this as follows:
+#
+# .. code-block:: bash
+#
+# $ cd $TVM_HOME/apps/microtvm
+# $ poetry lock && poetry install
+# $ poetry shell
+#
+# You should now be in a Python virtual environment with all of the appropriate
+# dependencies installed.
+#
+# Install Zephyr
+# ^^^^^^^^^^^^^^
+#
+# microTVM currently uses the `Zephyr <https://zephyrproject.org>` RTOS as
+# the basis for the device-side runtime. To get started, install Zephyr
+# and an appropriate device-specific toolchain using the
+# `Zephyr installation instructions
<https://docs.zephyrproject.org/latest/getting_started/index.html>`_.
+#
+# Be sure you are able to build and flash a sample Zephyr program
+# (e.g., the "Blinky" demo) to your device before you proceed with this
tutorial.
+
+import datetime
+import io
+import os
+import sys
+
+import onnx
+import tvm
+import tvm.micro
+from tvm import autotvm
+from tvm import relay
+from tvm.contrib import graph_runtime as runtime
+from tvm.micro.contrib import zephyr
+from PIL import Image
+import numpy as np
+
+######################################################################
+# For this tutorial, we use a pretrained ONNX model implementing
+# the MNIST handwritten digit recognition on 28x28 px input images.
+
+MODEL_FILE = "../../tests/micro/zephyr/testdata/mnist-8.onnx"
+MODEL_SHAPE = (1, 1, 28, 28)
+INPUT_TENSOR_NAME = "Input3"
+
+onnx_model = onnx.load(MODEL_FILE)
+print(f"Loaded ONNX model: {MODEL_FILE}")
+
+######################################################################
+# Next, we convert the model to Relay format.
+relay_mod, params = relay.frontend.from_onnx(onnx_model, shape=MODEL_SHAPE,
freeze_params=True)
+relay_mod = relay.transform.DynamicToStatic()(relay_mod)
+
+######################################################################
+# Next, we lower the Relay model to the specific device we are
+# targeting. In this case, we are using the Nordic Semiconductor
+# `nRF5340DK development board
<https://www.nordicsemi.com/Software-and-tools/Development-Kits/nRF5340-DK>`.
+
+# This is the device target name used by microTVM. It is used to select default
+# options for the device when we use ``tvm.target.target.micro()`` below.
+UTVM_TARGET = "nrf5340dk"
+
+# This is the board designation used by Zephyr, and required for the
compilation process.
+UTVM_ZEPHYR_BOARD = "nrf5340dk_nrf5340_cpuapp"
+
+######################################################################
+# If you wish to run against an emulated Zephyr device using QEMU,
+# you can uncomment these lines instead:
+# UTVM_TARGET = "host"
+# UTVM_ZEPHYR_BOARD = "qemu_x86"
+
+
+######################################################################
+# We define the TVM target here.
+# We add -link-params=1 option here, so that the model parameters are
+# included in the resulting binary image.
+target = tvm.target.target.micro(UTVM_TARGET, options=["-link-params=1"])
+
+######################################################################
+# Now, we do the Relay build.
+TVM_OPT_LEVEL = 3
+with tvm.transform.PassContext(opt_level=TVM_OPT_LEVEL,
config={"tir.disable_vectorize": True}):
+ lowered = relay.build(relay_mod, target, params=params)
+ graph_json_str = lowered.get_json()
+
+######################################################################
+# Next, create a uTVM Workspace. This is a location where the
+# generated Zephyr project will be compiled.
+workspace_root = os.path.abspath(
+ f'workspace/{datetime.datetime.now().strftime("%Y-%m-%dT%H-%M-%S")}'
+)
+workspace_parent = os.path.dirname(workspace_root)
+if not os.path.exists(workspace_parent):
+ os.makedirs(workspace_parent)
+workspace = tvm.micro.Workspace(debug=True, root=workspace_root)
+print(f"Using workspace: {workspace_root}")
+
+######################################################################
+# Now we create the ``ZephyrCompiler`` object, which generates the
+# Zephyr project for hosting the device runtime code, as well as
+# generating the device-specific binary from our model.
+
+# You are welcome to implement your own Zephyr-based runtime environment
+# for your project. This runtime is a demo which provides basic capabilities
+# for interfacing to the microTVM device code via the device's serial
+# port.
+UTVM_ZEPHYR_RUNTIME_DIR = "../../apps/microtvm/zephyr/demo_runtime/"
+
+# The ``west`` command is used by Zephyr for compilation and
+# flashing devices.
+UTVM_WEST_CMD = "west"
+
+compiler = zephyr.ZephyrCompiler(
+ project_dir=UTVM_ZEPHYR_RUNTIME_DIR,
+ board=UTVM_ZEPHYR_BOARD,
+ zephyr_toolchain_variant="zephyr",
Review comment:
For the nRF5340, I used this:
https://infocenter.nordicsemi.com/topic/ug_gsg_ncs/UG/gsg/install_toolchain.html
https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/gs_installing.html
- Launch Toolchain Manager from nRF Connect
- Once installed, select "Launch IDE"
- Open a project, e.g., the Zephyr samples "Blinky"
- Make sure that "Project 'zephyr/zephyr.elf'" is highlighted in the
projects panel
- Build > Build Solution
- Target > Connect J-Link
- Target > Download zephyr/zephyr.elf
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]