This works for me:
mingw32-make -f Makefile.tflite CC=gcc CXX=g++
edit: Actually, this lacks the porting layer (where to get timing info) on Windows… I’ll look at adding something here in the coming week.
edit 2: We’ll have a fix come in this week. In the meantime you can get around this by creating:
edge-impulse-sdk/porting/mingw32/debug_log.cpp
#include "../ei_classifier_porting.h"
#if EI_PORTING_MINGW32 == 1
#include "tensorflow/lite/micro/debug_log.h"
#include <stdio.h>
#include <stdarg.h>
// Redirect TFLite DebugLog to ei_printf
#if defined(__cplusplus) && EI_C_LINKAGE == 1
extern "C"
#endif // defined(__cplusplus) && EI_C_LINKAGE == 1
void DebugLog(const char* s) {
ei_printf("%s", s);
}
#endif // EI_PORTING_MINGW32 == 1
edge-impulse-sdk/porting/mingw32/ei_classifier_porting.cpp
#include "../ei_classifier_porting.h"
#if EI_PORTING_MINGW32 == 1
#include <inttypes.h>
#include <math.h>
#include <stdio.h>
#include <chrono>
#include <unistd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
EI_IMPULSE_ERROR ei_run_impulse_check_canceled() {
return EI_IMPULSE_OK;
}
/**
* Cancelable sleep, can be triggered with signal from other thread
*/
EI_IMPULSE_ERROR ei_sleep(int32_t time_ms) {
usleep(time_ms * 1000);
return EI_IMPULSE_OK;
}
uint64_t ei_read_timer_ms() {
auto now = std::chrono::system_clock::now();
auto duration = now.time_since_epoch();
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
return static_cast<uint64_t>(millis);
}
uint64_t ei_read_timer_us() {
auto now = std::chrono::system_clock::now();
auto duration = now.time_since_epoch();
auto micros = std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
return static_cast<uint64_t>(micros);
}
void ei_printf(const char *format, ...) {
va_list myargs;
va_start(myargs, format);
vprintf(format, myargs);
va_end(myargs);
}
void ei_printf_float(float f) {
ei_printf("%f", f);
}
void *ei_malloc(size_t size) {
return malloc(size);
}
void *ei_calloc(size_t nitems, size_t size) {
return calloc(nitems, size);
}
void ei_free(void *ptr) {
free(ptr);
}
#endif // EI_PORTING_MINGW32 == 1
Then, update edge-impulse-sdk/porting/ei_classifier_porting.h to read:
#ifndef _EI_CLASSIFIER_PORTING_H_
#define _EI_CLASSIFIER_PORTING_H_
#include <stdint.h>
#include <stdlib.h>
#include "tensorflow/lite/micro/debug_log.h"
#if defined(__cplusplus) && EI_C_LINKAGE == 1
extern "C" {
#endif // defined(__cplusplus)
typedef enum {
EI_IMPULSE_OK = 0,
EI_IMPULSE_ERROR_SHAPES_DONT_MATCH = -1,
EI_IMPULSE_CANCELED = -2,
EI_IMPULSE_TFLITE_ERROR = -3,
EI_IMPULSE_DSP_ERROR = -5,
EI_IMPULSE_TFLITE_ARENA_ALLOC_FAILED = -6,
EI_IMPULSE_CUBEAI_ERROR = -7,
EI_IMPULSE_ALLOC_FAILED = -8,
EI_IMPULSE_ONLY_SUPPORTED_FOR_IMAGES = -9,
EI_IMPULSE_UNSUPPORTED_INFERENCING_ENGINE = -10,
EI_IMPULSE_OUT_OF_MEMORY = -11
} EI_IMPULSE_ERROR;
/**
* Cancelable sleep, can be triggered with signal from other thread
*/
EI_IMPULSE_ERROR ei_sleep(int32_t time_ms);
/**
* Check if the sampler thread was canceled, use this in conjunction with
* the same signaling mechanism as ei_sleep
*/
EI_IMPULSE_ERROR ei_run_impulse_check_canceled();
/**
* Read the millisecond timer
*/
uint64_t ei_read_timer_ms();
/**
* Read the microsecond timer
*/
uint64_t ei_read_timer_us();
/**
* Print wrapper around printf()
* This is used internally to print debug information.
*/
void ei_printf(const char *format, ...);
/**
* Override this function if your target cannot properly print floating points
* If not overriden, this will be sent through `ei_printf()`.
*/
void ei_printf_float(float f);
/**
* Wrapper around malloc
*/
void *ei_malloc(size_t size);
/**
* Wrapper around calloc
*/
void *ei_calloc(size_t nitems, size_t size);
/**
* Wrapper around free
*/
void ei_free(void *ptr);
#if defined(__cplusplus) && EI_C_LINKAGE == 1
}
#endif // defined(__cplusplus) && EI_C_LINKAGE == 1
// Load porting layer depending on target
#ifndef EI_PORTING_ARDUINO
#ifdef ARDUINO
#define EI_PORTING_ARDUINO 1
#else
#define EI_PORTING_ARDUINO 0
#endif
#endif
#ifndef EI_PORTING_ECM3532
#ifdef ECM3532
#define EI_PORTING_ECM3532 1
#else
#define EI_PORTING_ECM3532 0
#endif
#endif
#ifndef EI_PORTING_MBED
#ifdef __MBED__
#define EI_PORTING_MBED 1
#else
#define EI_PORTING_MBED 0
#endif
#endif
#ifndef EI_PORTING_POSIX
#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
#define EI_PORTING_POSIX 1
#else
#define EI_PORTING_POSIX 0
#endif
#endif
#ifndef EI_PORTING_SILABS
#if defined(EFR32MG12P332F1024GL125)
#define EI_PORTING_SILABS 1
#else
#define EI_PORTING_SILABS 0
#endif
#endif
#ifndef EI_PORTING_ZEPHYR
#if defined(__ZEPHYR__)
#define EI_PORTING_ZEPHYR 1
#else
#define EI_PORTING_ZEPHYR 0
#endif
#endif
#ifndef EI_PORTING_STM32_CUBEAI
#if defined(USE_HAL_DRIVER) && !defined(__MBED__) && EI_PORTING_ZEPHYR == 0
#define EI_PORTING_STM32_CUBEAI 1
#else
#define EI_PORTING_STM32_CUBEAI 0
#endif
#endif
#ifndef EI_PORTING_HIMAX
#ifdef CPU_ARC
#define EI_PORTING_HIMAX 1
#else
#define EI_PORTING_HIMAX 0
#endif
#endif
#ifndef EI_PORTING_MINGW32
#ifdef __MINGW32__
#define EI_PORTING_MINGW32 1
#else
#define EI_PORTING_MINGW32 0
#endif
#endif
// End load porting layer depending on target
#endif // _EI_CLASSIFIER_PORTING_H_
Then, update Makefile.tflite to read:
NAME = edge-impulse-standalone
CC = gcc
CXX = g++
CFLAGS ?= -Wall
MACROS += -DTF_LITE_DISABLE_X86_NEON
CXXFLAGS += -std=c++11
CFLAGS += -I.
CFLAGS += -Isource
CFLAGS += -Iedge-impulse-sdk/
CFLAGS += -Iedge-impulse-sdk/tensorflow
CFLAGS += -Iedge-impulse-sdk/third_party
CFLAGS += -Iedge-impulse-sdk/third_party/flatbuffers
CFLAGS += -Iedge-impulse-sdk/third_party/flatbuffers/include
CFLAGS += -Iedge-impulse-sdk/third_party/flatbuffers/include/flatbuffers
CFLAGS += -Iedge-impulse-sdk/third_party/gemmlowp/
CFLAGS += -Iedge-impulse-sdk/third_party/gemmlowp/fixedpoint
CFLAGS += -Iedge-impulse-sdk/third_party/gemmlowp/internal
CFLAGS += -Iedge-impulse-sdk/third_party/ruy
CFLAGS += -Imodel-parameters
CFLAGS += -Itflite-model
CFLAGS += -Iedge-impulse-sdk/anomaly
CFLAGS += -Iedge-impulse-sdk/classifier
CFLAGS += -Iedge-impulse-sdk/dsp
CFLAGS += -Iedge-impulse-sdk/dsp/kissfft
CFLAGS += -Iedge-impulse-sdk/porting
CFLAGS += -lstdc++
CFLAGS += -lm
CFLAGS += -Os
CFLAGS += -DNDEBUG
CFLAGS += -g
ifeq ($(OS),Windows_NT)
MKDIR_BUILD = if not exist build mkdir build
else
MKDIR_BUILD = mkdir -p build
endif
all: build
.PHONY: build clean
build:
$(MKDIR_BUILD)
$(CC) -c $(MACROS) $(CFLAGS) $(LFLAGS) edge-impulse-sdk/tensorflow/lite/c/common.c -o build/common.o
$(CXX) $(MACROS) $(CXXFLAGS) $(CFLAGS) $(LFLAGS) source/*.cpp edge-impulse-sdk/dsp/kissfft/*.cpp edge-impulse-sdk/dsp/dct/*.cpp edge-impulse-sdk/tensorflow/lite/kernels/*.cc edge-impulse-sdk/tensorflow/lite/kernels/internal/*.cc edge-impulse-sdk/tensorflow/lite/micro/kernels/*.cc edge-impulse-sdk/tensorflow/lite/micro/*.cc edge-impulse-sdk/tensorflow/lite/micro/memory_planner/*.cc edge-impulse-sdk/tensorflow/lite/core/api/*.cc ./edge-impulse-sdk/dsp/memory.cpp edge-impulse-sdk/porting/posix/*.c* edge-impulse-sdk/porting/mingw32/*.c* tflite-model/*.cpp build/common.o -o build/$(NAME)
clean:
rm $(NAME)