You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by le...@apache.org on 2022/02/10 09:12:24 UTC
[tvm] branch main updated: Add FreeRTOS variant of NPU demo (#10004)
This is an automated email from the ASF dual-hosted git repository.
leandron pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/main by this push:
new e50a923 Add FreeRTOS variant of NPU demo (#10004)
e50a923 is described below
commit e50a923671905f59bd34bd2146e0cfee477242df
Author: Christopher Sidebottom <ch...@arm.com>
AuthorDate: Thu Feb 10 09:11:58 2022 +0000
Add FreeRTOS variant of NPU demo (#10004)
* Add FreeRTOS variant of NPU demo
This adds an extra flag to the existing NPU demo that runs it using the
FreeRTOS kernel task scheduling and queues.
* Add FreeRTOS notes to tutorial
* Update FreeRTOS demo to run in demo script
Also, minor text fixes.
* Minor text fixes
* Fix docs formatting
---
apps/microtvm/ethosu/.gitignore | 3 +
apps/microtvm/ethosu/Makefile | 21 +++-
apps/microtvm/ethosu/README.md | 7 +-
apps/microtvm/ethosu/include/FreeRTOSConfig.h | 112 ++++++++++++++++++
apps/microtvm/ethosu/include/tvm_runtime.h | 2 +-
apps/microtvm/ethosu/run_demo.sh | 14 ++-
.../ethosu/src/{demo.c => demo_bare_metal.c} | 0
apps/microtvm/ethosu/src/demo_freertos.c | 131 +++++++++++++++++++++
apps/microtvm/zephyr_cmsisnn/run_demo.sh | 1 -
gallery/how_to/work_with_microtvm/micro_ethosu.py | 13 ++
tests/scripts/task_cpp_unittest.sh | 14 ---
tests/scripts/task_demo_microtvm.sh | 9 ++
12 files changed, 307 insertions(+), 20 deletions(-)
diff --git a/apps/microtvm/ethosu/.gitignore b/apps/microtvm/ethosu/.gitignore
new file mode 100644
index 0000000..3ef8f08
--- /dev/null
+++ b/apps/microtvm/ethosu/.gitignore
@@ -0,0 +1,3 @@
+include/inputs.h
+include/outputs.h
+include/labels.h
diff --git a/apps/microtvm/ethosu/Makefile b/apps/microtvm/ethosu/Makefile
index d76bf90..1c4af77 100644
--- a/apps/microtvm/ethosu/Makefile
+++ b/apps/microtvm/ethosu/Makefile
@@ -58,6 +58,23 @@ $(else)
QUIET ?= @
$(endif)
+ifdef FREERTOS_PATH
+DEMO_MAIN = src/demo_freertos.c
+FREERTOS_KERNEL = $(FREERTOS_PATH)/FreeRTOS/Source
+FREERTOS_FLAGS = -I$(FREERTOS_KERNEL)/include/ \
+ -I$(FREERTOS_KERNEL)/portable/GCC/ARM_CM33_NTZ/non_secure/
+FREERTOS_SOURCES = $(FREERTOS_KERNEL)/portable/GCC/ARM_CM33_NTZ/non_secure/port.c \
+ $(FREERTOS_KERNEL)/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.c \
+ $(FREERTOS_KERNEL)/tasks.c \
+ $(FREERTOS_KERNEL)/list.c \
+ $(FREERTOS_KERNEL)/queue.c \
+ $(FREERTOS_KERNEL)/timers.c \
+ $(FREERTOS_KERNEL)/event_groups.c \
+ $(FREERTOS_KERNEL)/portable/MemMang/heap_3.c
+else
+DEMO_MAIN = src/demo_bare_metal.c
+endif
+
CODEGEN_SRCS = $(wildcard $(abspath $(BUILD_DIR))/codegen/host/src/*.c)
CODEGEN_OBJS = $(subst .c,.o,$(CODEGEN_SRCS))
CMSIS_STARTUP_SRCS = $(wildcard ${CMSIS_PATH}/Device/ARM/${ARM_CPU}/Source/*.c)
@@ -99,9 +116,9 @@ ${BUILD_DIR}/cmsis_nn/Source/SoftmaxFunctions/libCMSISNNSoftmax.a:
$(QUIET)cd $(abspath $(BUILD_DIR)/cmsis_nn) && $(MAKE) CMSISNNSoftmax
# Build demo application
-$(BUILD_DIR)/demo: src/demo.c src/tvm_ethosu_runtime.c $(UART_SRCS) $(BUILD_DIR)/stack_allocator.o $(BUILD_DIR)/crt_backend_api.o ${BUILD_DIR}/libcodegen.a ${BUILD_DIR}/libcmsis_startup.a ${BUILD_DIR}/ethosu_core_driver/libethosu_core_driver.a ${BUILD_DIR}/cmsis_nn/Source/SoftmaxFunctions/libCMSISNNSoftmax.a
+$(BUILD_DIR)/demo: $(DEMO_MAIN) src/tvm_ethosu_runtime.c $(FREERTOS_SOURCES) $(UART_SRCS) $(BUILD_DIR)/stack_allocator.o $(BUILD_DIR)/crt_backend_api.o ${BUILD_DIR}/libcodegen.a ${BUILD_DIR}/libcmsis_startup.a ${BUILD_DIR}/ethosu_core_driver/libethosu_core_driver.a ${BUILD_DIR}/cmsis_nn/Source/SoftmaxFunctions/libCMSISNNSoftmax.a
$(QUIET)mkdir -p $(@D)
- $(QUIET)$(CC) $(PKG_CFLAGS) -o $@ $^ $(PKG_LDFLAGS)
+ $(QUIET)$(CC) $(PKG_CFLAGS) $(FREERTOS_FLAGS) -o $@ $^ $(PKG_LDFLAGS)
clean:
$(QUIET)rm -rf $(BUILD_DIR)/codegen
diff --git a/apps/microtvm/ethosu/README.md b/apps/microtvm/ethosu/README.md
index e681b29..1f08928 100644
--- a/apps/microtvm/ethosu/README.md
+++ b/apps/microtvm/ethosu/README.md
@@ -58,12 +58,17 @@ export PATH=/opt/arm/FVP_Corstone_SSE-300/models/Linux64_GCC-6.4:/opt/arm/cmake/
Running the demo application
----------------------------
-Type the following command to run the demo application:
+Type the following command to run the bare metal demo application ([src/demo_bare_metal.c](./src/demo_bare_metal.c)):
```bash
./run_demo.sh
```
+To run the demo using FreeRTOS task scheduling and queues ([src/demo_freertos.c](./src/demo_freertos.c)), specify the path to FreeRTOS using `--freertos_path`, for example:
+```
+./run_demo.sh --freertos_path /opt/freertos/FreeRTOSv202112.00/
+```
+
If the Ethos(TM)-U driver and/or CMSIS have not been installed in /opt/arm/ethosu then
the locations for these can be specified as arguments to run_demo.sh, for example:
diff --git a/apps/microtvm/ethosu/include/FreeRTOSConfig.h b/apps/microtvm/ethosu/include/FreeRTOSConfig.h
new file mode 100644
index 0000000..a123581
--- /dev/null
+++ b/apps/microtvm/ethosu/include/FreeRTOSConfig.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+/* Please refer to http://www.freertos.org/a00110.html for refernce. */
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+/******************************************************************************
+ * Defines
+ **********SYSTEM_CORE_CLOCK********************************************************************/
+/* Hardware features */
+#define configENABLE_MPU 0
+#define configENABLE_FPU 0
+#define configENABLE_TRUSTZONE 0
+/* Scheduling */
+#define configCPU_CLOCK_HZ 25000000
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
+#define configUSE_PREEMPTION 1
+#define configUSE_TIME_SLICING 0
+#define configMAX_PRIORITIES 5
+#define configIDLE_SHOULD_YIELD 1
+#define configUSE_16_BIT_TICKS 0
+#define configRUN_FREERTOS_SECURE_ONLY 1
+/* Stack and heap */
+#define configMINIMAL_STACK_SIZE (uint16_t)128
+#define configMINIMAL_SECURE_STACK_SIZE 1024
+#define configTOTAL_HEAP_SIZE (size_t)(50 * 1024)
+#define configMAX_TASK_NAME_LEN 12
+/* OS features */
+#define configUSE_MUTEXES 1
+#define configUSE_TICKLESS_IDLE 1
+#define configUSE_APPLICATION_TASK_TAG 0
+#define configUSE_NEWLIB_REENTRANT 0
+#define configUSE_CO_ROUTINES 0
+#define configUSE_COUNTING_SEMAPHORES 1
+#define configUSE_RECURSIVE_MUTEXES 1
+#define configUSE_QUEUE_SETS 0
+#define configUSE_TASK_NOTIFICATIONS 1
+#define configUSE_TRACE_FACILITY 1
+/* Hooks */
+#define configUSE_IDLE_HOOK 0
+#define configUSE_TICK_HOOK 0
+#define configUSE_MALLOC_FAILED_HOOK 0
+/* Debug features */
+#define configCHECK_FOR_STACK_OVERFLOW 0
+#define configASSERT(x) \
+ if ((x) == 0) { \
+ taskDISABLE_INTERRUPTS(); \
+ for (;;) \
+ ; \
+ }
+#define configQUEUE_REGISTRY_SIZE 0
+/* Timers and queues */
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
+#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
+#define configTIMER_QUEUE_LENGTH 5
+/* Task settings */
+#define INCLUDE_vTaskPrioritySet 1
+#define INCLUDE_uxTaskPriorityGet 1
+#define INCLUDE_vTaskDelete 1
+#define INCLUDE_vTaskCleanUpResources 0
+#define INCLUDE_vTaskSuspend 1
+#define INCLUDE_vTaskDelayUntil 1
+#define INCLUDE_vTaskDelay 1
+#define INCLUDE_uxTaskGetStackHighWaterMark 0
+#define INCLUDE_xTaskGetIdleTaskHandle 0
+#define INCLUDE_eTaskGetState 1
+#define INCLUDE_xTaskResumeFromISR 0
+#define INCLUDE_xTaskGetCurrentTaskHandle 1
+#define INCLUDE_xTaskGetSchedulerState 0
+#define INCLUDE_xSemaphoreGetMutexHolder 0
+#define INCLUDE_xTimerPendFunctionCall 1
+#define configUSE_STATS_FORMATTING_FUNCTIONS 1
+#define configCOMMAND_INT_MAX_OUTPUT_SIZE 2048
+#ifdef __NVIC_PRIO_BITS
+#define configPRIO_BITS __NVIC_PRIO_BITS
+#else
+#define configPRIO_BITS 3
+#endif
+/* Interrupt settings */
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x07
+#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
+#define configKERNEL_INTERRUPT_PRIORITY \
+ (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY \
+ (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
+#ifndef __IASMARM__
+#define configGENERATE_RUN_TIME_STATS 0
+#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
+#define portGET_RUN_TIME_COUNTER_VALUE() 0
+#define configTICK_RATE_HZ (TickType_t)1000
+#endif /* __IASMARM__ */
+#define xPortPendSVHandler PendSV_Handler
+#define vPortSVCHandler SVC_Handler
+#define xPortSysTickHandler SysTick_Handler
+#endif /* FREERTOS_CONFIG_H */
diff --git a/apps/microtvm/ethosu/include/tvm_runtime.h b/apps/microtvm/ethosu/include/tvm_runtime.h
index 09d766e..3ab9981 100644
--- a/apps/microtvm/ethosu/include/tvm_runtime.h
+++ b/apps/microtvm/ethosu/include/tvm_runtime.h
@@ -57,4 +57,4 @@ TVM_DLL int TVMFuncRegisterGlobal(const char* name, TVMFunctionHandle f, int ove
#ifdef __cplusplus
}
-#endif
\ No newline at end of file
+#endif
diff --git a/apps/microtvm/ethosu/run_demo.sh b/apps/microtvm/ethosu/run_demo.sh
index 7c2bb09..18d82f7 100755
--- a/apps/microtvm/ethosu/run_demo.sh
+++ b/apps/microtvm/ethosu/run_demo.sh
@@ -71,6 +71,18 @@ while (( $# )); do
fi
;;
+ --freertos_path)
+ if [ $# -gt 1 ]
+ then
+ export FREERTOS_PATH="$2"
+ shift 2
+ else
+ echo 'ERROR: --freertos_path requires a non-empty argument' >&2
+ show_usage >&2
+ exit 1
+ fi
+ ;;
+
--ethosu_platform_path)
if [ $# -gt 1 ]
then
@@ -105,7 +117,7 @@ while (( $# )); do
show_usage >&2
exit 1
fi
- ;;
+ ;;
-*|--*)
echo "Error: Unknown flag: $1" >&2
diff --git a/apps/microtvm/ethosu/src/demo.c b/apps/microtvm/ethosu/src/demo_bare_metal.c
similarity index 100%
rename from apps/microtvm/ethosu/src/demo.c
rename to apps/microtvm/ethosu/src/demo_bare_metal.c
diff --git a/apps/microtvm/ethosu/src/demo_freertos.c b/apps/microtvm/ethosu/src/demo_freertos.c
new file mode 100644
index 0000000..cd5b76b
--- /dev/null
+++ b/apps/microtvm/ethosu/src/demo_freertos.c
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+#include <FreeRTOS.h>
+#include <queue.h>
+#include <stdio.h>
+#include <task.h>
+#include <tvm_runtime.h>
+
+#include "ethosu_mod.h"
+#include "uart.h"
+
+// Header files generated by convert_image.py and convert_labels.py
+#include "inputs.h"
+#include "labels.h"
+#include "outputs.h"
+
+static void prvInferenceTask(void* pvParameters);
+static void prvDataCollectionTask(void* pvParameters);
+
+#define mainQUEUE_INFERENCE_TASK_PRIORITY (tskIDLE_PRIORITY + 3)
+#define mainQUEUE_INFERENCE_TASK_STACK_SIZE 4096
+#define mainQUEUE_DATA_TASK_PRIORITY (tskIDLE_PRIORITY + 2)
+#define mainQUEUE_DATA_TASK_STACK_SIZE configMINIMAL_STACK_SIZE
+#define mainQUEUE_LENGTH (1)
+#define mainQUEUE_SEND_FREQUENCY_MS (100 / portTICK_PERIOD_MS)
+
+/* The queue used to pass data to run through our model */
+static QueueHandle_t xQueue = NULL;
+
+int main(void) {
+ // Platform UART
+ uart_init();
+ // NPU
+ EthosuInit();
+ // TVM Memory Manager
+ StackMemoryManager_Init(&app_workspace, g_aot_memory, WORKSPACE_SIZE);
+
+ // Queue for inferences
+ xQueue = xQueueCreate(mainQUEUE_LENGTH, sizeof(uint8_t*));
+
+ if (xQueue != NULL) {
+ // Inference task
+ xTaskCreate(prvInferenceTask, "Inference", mainQUEUE_INFERENCE_TASK_STACK_SIZE, NULL,
+ mainQUEUE_INFERENCE_TASK_PRIORITY, NULL);
+
+ // Data collector task
+ xTaskCreate(prvDataCollectionTask, "Data", mainQUEUE_DATA_TASK_STACK_SIZE, NULL,
+ mainQUEUE_DATA_TASK_PRIORITY, NULL);
+
+ // Start the task scheduling
+ vTaskStartScheduler();
+ }
+
+ // The task scheduler should take over before this is reached
+ printf("Unreachable code reached!\n");
+}
+
+/*
+ * This task emulates collection of data and sending it to another inference task
+ * for processing
+ */
+static void prvDataCollectionTask(void* pvParameters) {
+ // Unused
+ (void)pvParameters;
+
+ // Working
+ vTaskDelay(mainQUEUE_SEND_FREQUENCY_MS);
+
+ // Construct pointer to copy to queue
+ uint8_t** pucInputData = &input;
+ xQueueSend(xQueue, &pucInputData, 0U);
+}
+
+/*
+ * This task emulates the inference of data sent by the collector task
+ */
+static void prvInferenceTask(void* pvParameters) {
+ uint8_t* pucReceivedData;
+
+ // Unused
+ (void)pvParameters;
+
+ // Wait for data collection
+ xQueueReceive(xQueue, &pucReceivedData, portMAX_DELAY);
+
+ // Print output of inference and exit task
+ printf("Running inference\n");
+ struct tvmgen_default_inputs xInputs = {
+ .tfl_quantize = pucReceivedData,
+ };
+ struct tvmgen_default_outputs xOutputs = {
+ .output = output,
+ };
+ struct ethosu_driver* xDriver = ethosu_reserve_driver();
+ struct tvmgen_default_devices xDevices = {
+ .ethos_u = xDriver,
+ };
+ tvmgen_default_run(&xInputs, &xOutputs, &xDevices);
+ ethosu_release_driver(xDriver);
+
+ // Calculate index of max value
+ int8_t ucMaxValue = -128;
+ int32_t lMaxIndex = -1;
+ for (unsigned int i = 0; i < output_len; ++i) {
+ if (output[i] > ucMaxValue) {
+ ucMaxValue = output[i];
+ lMaxIndex = i;
+ }
+ }
+ printf("The image has been classified as '%s'\n", labels[lMaxIndex]);
+
+ // The FVP will shut down when it receives "EXITTHESIM" on the UART
+ printf("EXITTHESIM\n");
+}
diff --git a/apps/microtvm/zephyr_cmsisnn/run_demo.sh b/apps/microtvm/zephyr_cmsisnn/run_demo.sh
index 13d163b..6588b56 100755
--- a/apps/microtvm/zephyr_cmsisnn/run_demo.sh
+++ b/apps/microtvm/zephyr_cmsisnn/run_demo.sh
@@ -45,7 +45,6 @@ export ARMFVP_BIN_PATH=/opt/arm/FVP_Corstone_SSE-300/models/Linux64_GCC-6.4/
west zephyr-export
west build
west build -t run &> ${LOGDIR}/west.log &
-WEST_PID=$!
# Wait for "exit" keyword
until grep -m 1 "exit" ${LOGDIR}/west.log; do sleep 1 ; done
diff --git a/gallery/how_to/work_with_microtvm/micro_ethosu.py b/gallery/how_to/work_with_microtvm/micro_ethosu.py
index 848db2e..ef34c7d 100644
--- a/gallery/how_to/work_with_microtvm/micro_ethosu.py
+++ b/gallery/how_to/work_with_microtvm/micro_ethosu.py
@@ -412,6 +412,12 @@ TVM to offload operators to the Ethos(TM)-U55 where possible.
# `include files <https://github.com/apache/tvm/tree/main/apps/microtvm/ethosu/include>`_
################################################################################
+# .. note::
+#
+# If you'd like to use FreeRTOS for task scheduling and queues, a sample application can be found here
+# `demo_freertos.c <https://github.com/apache/tvm/blob/main/apps/microtvm/ethosu/src/demo_freertos.c>`
+
+################################################################################
# Creating the linker script
# --------------------------
#
@@ -454,6 +460,13 @@ TVM to offload operators to the Ethos(TM)-U55 where possible.
# `Makefile <https://github.com/apache/tvm/blob/main/apps/microtvm/ethosu/Makefile>`_
################################################################################
+# .. note::
+#
+# If you're using FreeRTOS, the Makefile builds it from the specified FREERTOS_PATH:
+# ``make FREERTOS_PATH=<FreeRTOS directory>``
+#
+
+################################################################################
# Running the demo application
# ----------------------------
#
diff --git a/tests/scripts/task_cpp_unittest.sh b/tests/scripts/task_cpp_unittest.sh
index e6c3669..3df7b58 100755
--- a/tests/scripts/task_cpp_unittest.sh
+++ b/tests/scripts/task_cpp_unittest.sh
@@ -45,17 +45,3 @@ cd apps/bundle_deploy
rm -rf build
make test_dynamic test_static
cd ../..
-
-# Test Arm(R) Cortex(R)-M55 CPU and Ethos(TM)-U55 NPU demo app
-FVP_PATH="/opt/arm/FVP_Corstone_SSE-300"
-
-# TODO(@grant-arm): Remove once ci_cpu docker image has been updated to FVP_Corstone_SSE
-if test ! -d $FVP_PATH; then
- FVP_PATH="/opt/arm/FVP_Corstone_SSE-300_Ethos-U55"
-fi
-
-if test -d $FVP_PATH && pip3 list | grep vela; then
- cd apps/microtvm/ethosu
- ./run_demo.sh --fvp_path $FVP_PATH --cmake_path /opt/arm/cmake/bin/cmake
- cd ../../..
-fi
diff --git a/tests/scripts/task_demo_microtvm.sh b/tests/scripts/task_demo_microtvm.sh
index 383e693..c569f6c 100755
--- a/tests/scripts/task_demo_microtvm.sh
+++ b/tests/scripts/task_demo_microtvm.sh
@@ -21,3 +21,12 @@ set -euxo pipefail
pushd apps/microtvm/zephyr_cmsisnn
./run_demo.sh
popd
+
+pushd apps/microtvm/ethosu
+FVP_PATH="/opt/arm/FVP_Corstone_SSE-300_Ethos-U55"
+CMAKE_PATH="/opt/arm/cmake/bin/cmake"
+FREERTOS_PATH="/opt/freertos/FreeRTOSv202112.00"
+
+./run_demo.sh --fvp_path $FVP_PATH --cmake_path $CMAKE_PATH
+./run_demo.sh --fvp_path $FVP_PATH --cmake_path $CMAKE_PATH --freertos_path $FREERTOS_PATH
+popd