blob: dde5dc5182ad9ab373b15b46ca492dd5132acff0 [file] [log] [blame]
Yulia Garbovichf61ea352021-11-11 14:16:57 +02001/*
Kristofer Jonssonac535f02022-03-10 11:08:39 +01002 * Copyright (c) 2019-2022 Arm Limited.
Yulia Garbovichf61ea352021-11-11 14:16:57 +02003 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19/****************************************************************************
20 * Includes
21 ****************************************************************************/
22
23#include "FreeRTOS.h"
24#include "queue.h"
25#include "semphr.h"
26#include "task.h"
27
28#include <inttypes.h>
29#include <stdio.h>
30
31#include "ethosu_core_interface.h"
32#include "message_handler.hpp"
33#include "message_queue.hpp"
34#include <mailbox.hpp>
35
36#if defined(MHU_V2)
37#include <mhu_v2.hpp>
38#elif defined(MHU_JUNO)
39#include <mhu_juno.hpp>
40#else
41#include <mhu_dummy.hpp>
42#endif
43
44/* Disable semihosting */
45__asm(".global __use_no_semihosting\n\t");
46
47using namespace EthosU;
48using namespace MessageHandler;
49
50/****************************************************************************
51 * Defines
52 ****************************************************************************/
53
54// Nr. of tasks to process inferences with, reserves driver & runs inference (Normally 1 per NPU, but not a must)
55#if defined(ETHOSU_NPU_COUNT)
56constexpr size_t NUM_PARALLEL_TASKS = ETHOSU_NPU_COUNT;
57#else
58constexpr size_t NUM_PARALLEL_TASKS = 1;
59#endif
60
61// TensorArena static initialisation
62constexpr size_t arenaSize = TENSOR_ARENA_SIZE / NUM_PARALLEL_TASKS;
63
64__attribute__((section(".bss.tensor_arena"), aligned(16))) uint8_t tensorArena[NUM_PARALLEL_TASKS][arenaSize];
65
66// Message queue from remote host
67__attribute__((section("ethosu_core_in_queue"))) MessageQueue::Queue<1000> inputMessageQueue;
68
69// Message queue to remote host
70__attribute__((section("ethosu_core_out_queue"))) MessageQueue::Queue<1000> outputMessageQueue;
71
72namespace {
Yulia Garbovichf61ea352021-11-11 14:16:57 +020073
Davide Grohmann134c39e2022-04-25 12:21:12 +020074SemaphoreHandle_t messageNotify;
75QueueHandle_t inferenceInputQueue;
76QueueHandle_t inferenceOutputQueue;
Yulia Garbovichf61ea352021-11-11 14:16:57 +020077
78// Mailbox driver
79#ifdef MHU_V2
80Mailbox::MHUv2 mailbox(MHU_TX_BASE_ADDRESS, MHU_RX_BASE_ADDRESS); // txBase, rxBase
81#elif defined(MHU_JUNO)
82Mailbox::MHUJuno mailbox(MHU_BASE_ADDRESS);
83#else
84Mailbox::MHUDummy mailbox;
85#endif
86
87} // namespace
88
89/****************************************************************************
90 * Mutex & Semaphore
91 ****************************************************************************/
92
93extern "C" {
94
95void *ethosu_mutex_create(void) {
96 return xSemaphoreCreateMutex();
97}
98
Ledion Daja60c57372022-04-05 15:04:11 +020099int ethosu_mutex_lock(void *mutex) {
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200100 SemaphoreHandle_t handle = reinterpret_cast<SemaphoreHandle_t>(mutex);
Ledion Daja60c57372022-04-05 15:04:11 +0200101 if (xSemaphoreTake(handle, portMAX_DELAY) != pdTRUE) {
102 printf("Error: Failed to lock mutex.\n");
103 return -1;
104 }
105 return 0;
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200106}
107
Ledion Daja60c57372022-04-05 15:04:11 +0200108int ethosu_mutex_unlock(void *mutex) {
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200109 SemaphoreHandle_t handle = reinterpret_cast<SemaphoreHandle_t>(mutex);
Ledion Daja60c57372022-04-05 15:04:11 +0200110 if (xSemaphoreGive(handle) != pdTRUE) {
111 printf("Error: Failed to unlock mutex.\n");
112 return -1;
113 }
114 return 0;
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200115}
116
117void *ethosu_semaphore_create(void) {
118 return xSemaphoreCreateBinary();
119}
120
Ledion Daja60c57372022-04-05 15:04:11 +0200121int ethosu_semaphore_take(void *sem) {
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200122 SemaphoreHandle_t handle = reinterpret_cast<SemaphoreHandle_t>(sem);
Ledion Daja60c57372022-04-05 15:04:11 +0200123 if (xSemaphoreTake(handle, portMAX_DELAY) != pdTRUE) {
124 printf("Error: Failed to take semaphore.\n");
125 return -1;
126 }
127 return 0;
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200128}
129
Ledion Daja60c57372022-04-05 15:04:11 +0200130int ethosu_semaphore_give(void *sem) {
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200131 SemaphoreHandle_t handle = reinterpret_cast<SemaphoreHandle_t>(sem);
Ledion Daja60c57372022-04-05 15:04:11 +0200132 if (xPortIsInsideInterrupt()) {
133 if (xSemaphoreGiveFromISR(handle, NULL) != pdTRUE) {
134 printf("Error: Failed to give semaphore from ISR.\n");
135 return -1;
136 }
137 } else {
138 /* A FreeRTOS binary semaphore is fundamentally a queue that can only hold one item. If the queue is full,
139 * xSemaphoreGive will return a pdFALSE value. Ignoring the return value in here, as a semaphore give failure
140 * does not affect the application correctness. */
141 if (xSemaphoreGive(handle) != pdTRUE) {
142 // do nothing
143 }
144 }
145 return 0;
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200146}
147}
148
149/****************************************************************************
150 * Application
151 ****************************************************************************/
152
153namespace {
154
Kristofer Jonsson29467e02021-11-26 16:10:43 +0100155#ifdef MHU_IRQ
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200156void mailboxIrqHandler() {
157 mailbox.handleMessage();
158}
Kristofer Jonsson29467e02021-11-26 16:10:43 +0100159#endif
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200160
161void inferenceTask(void *pvParameters) {
162 printf("Starting inference task\n");
163
164 uint8_t *arena = reinterpret_cast<uint8_t *>(pvParameters);
Davide Grohmann134c39e2022-04-25 12:21:12 +0200165 InferenceHandler process(arena, arenaSize, inferenceInputQueue, inferenceOutputQueue, messageNotify);
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200166 process.run();
167}
168
Davide Grohmann134c39e2022-04-25 12:21:12 +0200169void messageTask(void *) {
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200170 printf("Starting input message task\n");
171
Davide Grohmann134c39e2022-04-25 12:21:12 +0200172 IncomingMessageHandler process(*inputMessageQueue.toQueue(),
173 *outputMessageQueue.toQueue(),
174 mailbox,
175 inferenceInputQueue,
176 inferenceOutputQueue,
177 messageNotify);
Kristofer Jonssond89ee0d2022-04-01 15:41:06 +0200178
179#ifdef MHU_IRQ
180 // Register mailbox interrupt handler
181 NVIC_SetVector((IRQn_Type)MHU_IRQ, (uint32_t)&mailboxIrqHandler);
182 NVIC_EnableIRQ((IRQn_Type)MHU_IRQ);
183#endif
184
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200185 process.run();
186}
187
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200188} // namespace
189
190// FreeRTOS application. NOTE: Additional tasks may require increased heap size.
191int main() {
192 BaseType_t ret;
193
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200194 if (!mailbox.verifyHardware()) {
195 printf("Failed to verify mailbox hardware\n");
196 return 1;
197 }
198
199 // Create message queues for inter process communication
Davide Grohmann134c39e2022-04-25 12:21:12 +0200200 messageNotify = xSemaphoreCreateBinary();
201 inferenceInputQueue = xQueueCreate(10, sizeof(ethosu_core_inference_req));
202 inferenceOutputQueue = xQueueCreate(10, sizeof(ethosu_core_inference_rsp));
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200203
204 // Task for handling incoming messages from the remote host
Davide Grohmann134c39e2022-04-25 12:21:12 +0200205 ret = xTaskCreate(messageTask, "messageTask", 1024, nullptr, 2, nullptr);
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200206 if (ret != pdPASS) {
Davide Grohmann134c39e2022-04-25 12:21:12 +0200207 printf("Failed to create 'messageTask'\n");
Yulia Garbovichf61ea352021-11-11 14:16:57 +0200208 return ret;
209 }
210
211 // One inference task for each NPU
212 for (size_t n = 0; n < NUM_PARALLEL_TASKS; n++) {
213 ret = xTaskCreate(inferenceTask, "inferenceTask", 8 * 1024, &tensorArena[n], 3, nullptr);
214 if (ret != pdPASS) {
215 printf("Failed to create 'inferenceTask%d'\n", n);
216 return ret;
217 }
218 }
219
220 // Start Scheduler
221 vTaskStartScheduler();
222
223 return 1;
224}