You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by GitBox <gi...@apache.org> on 2021/03/05 20:48:50 UTC

[GitHub] [tvm] mdw-octoml commented on a change in pull request #7557: Clean up uTVM demo runtime, add ONNX model test and tutorial

mdw-octoml commented on a change in pull request #7557:
URL: https://github.com/apache/tvm/pull/7557#discussion_r585892739



##########
File path: apps/microtvm/pyproject.toml
##########
@@ -47,12 +50,12 @@ exclude = '''
 )
 '''
 [tool.poetry]
-name = "tvm"
+name = "microtvm"
 version = "0.1.0"
 description = ""
-authors = ["Your Name <yo...@example.com>"]
+authors = ["Andrew Reusch <ar...@octoml.ai>"]

Review comment:
       Done.

##########
File path: apps/microtvm/README.md
##########
@@ -15,14 +15,17 @@
 <!--- specific language governing permissions and limitations -->
 <!--- under the License. -->
 
-# microTVM Reference Virtual Machines
+# microTVM
 
+microTVM is the effort that allows TVM to build and execute models on bare-metal microcontrollers.
 
-microTVM is the effort to allow TVM to build and execute models on bare-metal microcontrollers.
-These Virtual Machines are used to reproduce results and bugs when using microTVM with real
-physical hardware. Note that they are not used to run Continuous Integration regression tests--
-those are instead run by the QEMU container (they run against an emulator, rather than real
-hardware).
+The `pyproject.toml` file in this directory can be used to create a
+[Poetry](https://python-poetry.org/) Python environment with all of the required
+dependencies installed. To use it, run:

Review comment:
       Done.

##########
File path: apps/microtvm/pyproject.toml
##########
@@ -66,6 +69,8 @@ tornado = "^6"
 typed_ast = "^1.4"
 pyyaml = "^5.4.1"
 pyserial = "^3.5"
+pyelftools = "^0.27"

Review comment:
       Not sure anymore. Removing it.

##########
File path: apps/microtvm/zephyr/demo_runtime/prj.conf
##########
@@ -15,6 +15,9 @@
 # specific language governing permissions and limitations
 # under the License.
 
+# The settings in this file are generic for all boards, and are merged

Review comment:
       Done.

##########
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.

Review comment:
       Done.

##########
File path: apps/microtvm/zephyr/demo_runtime/src/main.c
##########
@@ -153,113 +190,132 @@ tvm_crt_error_t TVMPlatformTimerStop(double* elapsed_time_seconds) {
   // if we approach the limits of the HW clock datatype (uint32_t), use the
   // coarse-grained timer result instead
   if (approx_num_cycles > (0.5 * (~((uint32_t)0)))) {
-    *elapsed_time_seconds = timer_res_ms / 1e3;
+    *res_us = timer_res_ms * 1000.0;
   } else {
-    *elapsed_time_seconds = hw_clock_elapsed_seconds;
+    *res_us = hw_clock_res_us;
   }
 
   g_utvm_timer_running = 0;
   return kTvmErrorNoError;
 }
 
-tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t* buffer, size_t num_bytes) {
-  uint32_t random;  // one unit of random data.
+// Memory pool for use by TVMPlatformMemoryAllocate.
+K_MEM_POOL_DEFINE(tvm_memory_pool, 64, 1024, 216, 4);
 
-  // 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);
-  }
+// Used by TVM to allocate memory.
+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;
+}
 
+// Used by TVM to deallocate memory.
+tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLContext ctx) {
+  k_free(ptr);
   return kTvmErrorNoError;
 }
 
-#define RING_BUF_SIZE 512
+// Ring buffer used to store data read from the UART on rx interrupt.
+#define RING_BUF_SIZE 20 * 1024

Review comment:
       Fixed!

##########
File path: python/tvm/micro/contrib/zephyr.py
##########
@@ -650,10 +650,10 @@ def popen_kwargs(self):
         env = dict(os.environ)
         env["ZEPHYR_BASE"] = self._zephyr_base
 
-        return dict(
+        args = dict(
             args=self._west_cmd
             + [
-                "debug",
+                "attach",

Review comment:
       This is the official Zephyr way of attaching a debugger to a running session. Otherwise `west debug` will reset the device, which means that the device will reboot when the debugger attaches. I think this should work on all devices, and is probably the right thing to do in all cases ... WDYT?

##########
File path: apps/microtvm/zephyr/demo_runtime/src/main.c
##########
@@ -153,113 +190,132 @@ tvm_crt_error_t TVMPlatformTimerStop(double* elapsed_time_seconds) {
   // if we approach the limits of the HW clock datatype (uint32_t), use the
   // coarse-grained timer result instead
   if (approx_num_cycles > (0.5 * (~((uint32_t)0)))) {
-    *elapsed_time_seconds = timer_res_ms / 1e3;
+    *res_us = timer_res_ms * 1000.0;
   } else {
-    *elapsed_time_seconds = hw_clock_elapsed_seconds;
+    *res_us = hw_clock_res_us;
   }
 
   g_utvm_timer_running = 0;
   return kTvmErrorNoError;
 }
 
-tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t* buffer, size_t num_bytes) {
-  uint32_t random;  // one unit of random data.
+// Memory pool for use by TVMPlatformMemoryAllocate.
+K_MEM_POOL_DEFINE(tvm_memory_pool, 64, 1024, 216, 4);
 
-  // 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);
-  }
+// Used by TVM to allocate memory.
+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;
+}
 
+// Used by TVM to deallocate memory.
+tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLContext ctx) {
+  k_free(ptr);
   return kTvmErrorNoError;
 }
 
-#define RING_BUF_SIZE 512
+// Ring buffer used to store data read from the UART on rx interrupt.
+#define RING_BUF_SIZE 20 * 1024

Review comment:
       Done.

##########
File path: tests/micro/zephyr/README.md
##########
@@ -0,0 +1,35 @@
+<!--- 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. -->
+
+This directory contains units tests for MicroTVM integration with Zephyr.
+
+To run the test, you first need to be running in a Python environment with
+all of the appropriate TVM dependencies installed. If you have [Poetry](https://python-poetry.org/)
+installed, you can do the following to get an appropriately-configured Python
+environment:
+
+```
+$ cd tvm/apps/microtvm/
+$ poetry lock && poetry install && poetry shell
+```
+
+You can then run this test using:
+
+```
+$ cd tvm/tests/micro/zephyr
+$ pytest test_zephyr.py --microtvm-platforms=nrf5340dk

Review comment:
       Fixed.

##########
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 dunno. I think this code was borrowed from the micro-blogpost-eval code. What do you recommend here?

##########
File path: apps/microtvm/zephyr/README.md
##########
@@ -0,0 +1,19 @@
+<!--- 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. -->
+
+This directory code to interface uTVM with the [Zephyr RTOS](https://zephyrproject.org/).

Review comment:
       Done.

##########
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;
   }
 
 #ifdef CONFIG_LED
-  gpio_pin_set(led_pin, PIN, 1);
+  gpio_pin_set(led0_pin, LED0_PIN, 1);
 #endif
   k_timer_start(&g_utvm_timer, TIME_TIL_EXPIRY, TIME_TIL_EXPIRY);
   g_utvm_start_time = k_cycle_get_32();
   g_utvm_timer_running = 1;
   return kTvmErrorNoError;
 }
 
-tvm_crt_error_t TVMPlatformTimerStop(double* elapsed_time_seconds) {
+// Used to stop system timer.
+tvm_crt_error_t TVMPlatformTimerStop(double* res_us) {

Review comment:
       Fixed.

##########
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.

Review comment:
       Done.

##########
File path: tests/micro/zephyr/test_zephyr.py
##########
@@ -201,6 +209,51 @@ def test_relay(platform, west_cmd):
         tvm.testing.assert_allclose(result, x_in * x_in + 1)
 
 
+def test_onnx(platform, west_cmd):
+    """Testing a simple ONNX model."""
+    model, zephyr_board = PLATFORMS[platform]
+
+    # Load test images.
+    digit_2 = Image.open("testdata/digit-2.jpg").resize((28, 28))
+    digit_2 = np.asarray(digit_2).astype("float32")
+    digit_2 = np.expand_dims(digit_2, axis=0)
+
+    digit_9 = Image.open("testdata/digit-9.jpg").resize((28, 28))
+    digit_9 = np.asarray(digit_9).astype("float32")
+    digit_9 = np.expand_dims(digit_9, axis=0)
+
+    # Load ONNX model and convert to Relay.
+    onnx_model = onnx.load("testdata/mnist-8.onnx")
+    shape = (1, 1, 28, 28)
+    relay_mod, params = relay.frontend.from_onnx(onnx_model, shape=shape, freeze_params=True)
+    relay_mod = relay.transform.DynamicToStatic()(relay_mod)
+
+    # We add the -link-params=1 option to ensure the model parameters are compiled in.
+    # There is currently a bug preventing the demo_runtime environment from receiving

Review comment:
       Added link.

##########
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.

Review comment:
       Done.

##########
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.

Review comment:
       Done.

##########
File path: tests/micro/zephyr/README.md
##########
@@ -0,0 +1,35 @@
+<!--- 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. -->
+
+This directory contains units tests for MicroTVM integration with Zephyr.
+
+To run the test, you first need to be running in a Python environment with
+all of the appropriate TVM dependencies installed. If you have [Poetry](https://python-poetry.org/)
+installed, you can do the following to get an appropriately-configured Python
+environment:
+
+```
+$ cd tvm/apps/microtvm/
+$ poetry lock && poetry install && poetry shell
+```
+
+You can then run this test using:

Review comment:
       Fixed. It works for both.

##########
File path: tests/micro/zephyr/README.md
##########
@@ -0,0 +1,35 @@
+<!--- 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. -->
+
+This directory contains units tests for MicroTVM integration with Zephyr.

Review comment:
       I just changed it to "tests" :-)
   




----------------------------------------------------------------
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:
users@infra.apache.org