Skip to content

Commit

Permalink
Add FreeRTOS variant of NPU demo (#10004)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Mousius authored Feb 10, 2022
1 parent 345eb09 commit e50a923
Show file tree
Hide file tree
Showing 12 changed files with 307 additions and 20 deletions.
3 changes: 3 additions & 0 deletions apps/microtvm/ethosu/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include/inputs.h
include/outputs.h
include/labels.h
21 changes: 19 additions & 2 deletions apps/microtvm/ethosu/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion apps/microtvm/ethosu/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
112 changes: 112 additions & 0 deletions apps/microtvm/ethosu/include/FreeRTOSConfig.h
Original file line number Diff line number Diff line change
@@ -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 */
2 changes: 1 addition & 1 deletion apps/microtvm/ethosu/include/tvm_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@ TVM_DLL int TVMFuncRegisterGlobal(const char* name, TVMFunctionHandle f, int ove

#ifdef __cplusplus
}
#endif
#endif
14 changes: 13 additions & 1 deletion apps/microtvm/ethosu/run_demo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -105,7 +117,7 @@ while (( $# )); do
show_usage >&2
exit 1
fi
;;
;;

-*|--*)
echo "Error: Unknown flag: $1" >&2
Expand Down
File renamed without changes.
131 changes: 131 additions & 0 deletions apps/microtvm/ethosu/src/demo_freertos.c
Original file line number Diff line number Diff line change
@@ -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");
}
1 change: 0 additions & 1 deletion apps/microtvm/zephyr_cmsisnn/run_demo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions gallery/how_to/work_with_microtvm/micro_ethosu.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,12 @@
#
# `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
# --------------------------
Expand Down Expand Up @@ -453,6 +459,13 @@
# An example Makefile can be found here:
# `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
# ----------------------------
Expand Down
14 changes: 0 additions & 14 deletions tests/scripts/task_cpp_unittest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading

0 comments on commit e50a923

Please sign in to comment.