Search code examples
google-coral

Cannot get USB to work on Raspberry-Pi Zero with Coral Edge TPU


I have cross compiled libedgetpu for Raspi-0 and I can run a minimal C++ program. However it does not detect any TPU's. (The Coral TPU is connected via USB port to the Pi-0).

pi@raspberrypi:~ $ lsusb
Bus 001 Device 004: ID 1a6e:089a Global Unichip Corp. 
Bus 001 Device 003: ID 0bda:8153 Realtek Semiconductor Corp. RTL8153 Gigabit Ethernet Adapter
Bus 001 Device 002: ID 1a40:0101 Terminus Technology Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

I added some debug statements in the code, here is the output:

pi@raspberrypi:/tmp $ LD_LIBRARY_PATH=. ./minimal 
1...
######## BuildFromFile..
libedgetpu/tflite/edgetpu_manager_direct.cc:242 #### EnumerateEdgeTpuInternal 1
libedgetpu/driver/driver_factory.cc:130 #### DriverFactory::GetOrCreate 1
libedgetpu/tflite/edgetpu_manager_direct.cc:250 #### EnumerateEdgeTpuInternal 2
libedgetpu/driver/driver_factory.cc:48 #### DriverFactory::Enumerate 1
libedgetpu/driver/driver_factory.cc:58 #### DriverFactory::Enumerate device_list.size:0
libedgetpu/tflite/edgetpu_manager_direct.cc:252 #### EnumerateEdgeTpuInternal 2, count:0
libedgetpu/tflite/edgetpu_manager_direct.cc:284 #### EnumerateEdgeTpuInternal 4
available_tpus.size: 0
2
libedgetpu/tflite/edgetpu_manager_direct.cc:242 #### EnumerateEdgeTpuInternal 1
libedgetpu/driver/driver_factory.cc:130 #### DriverFactory::GetOrCreate 1
libedgetpu/tflite/edgetpu_manager_direct.cc:250 #### EnumerateEdgeTpuInternal 2
libedgetpu/driver/driver_factory.cc:48 #### DriverFactory::Enumerate 1
libedgetpu/driver/driver_factory.cc:58 #### DriverFactory::Enumerate device_list.size:0
libedgetpu/tflite/edgetpu_manager_direct.cc:252 #### EnumerateEdgeTpuInternal 2, count:0
libedgetpu/tflite/edgetpu_manager_direct.cc:284 #### EnumerateEdgeTpuInternal 4
3
INFO: Initialized TensorFlow Lite runtime.
3.1
3.2
3.3
ERROR: Failed to retrieve TPU context.
ERROR: Node number 0 (edgetpu-custom-op) failed to prepare.

Failed to allocate tensors.
Done

Here is my main.cc

#include <iostream>
#include <memory>

#include "edgetpu.h"
#include "tensorflow/lite/builtin_op_data.h"
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"

namespace  {
std::unique_ptr<tflite::Interpreter> BuildEdgeTpuInterpreter(
    const tflite::FlatBufferModel& model,
    edgetpu::EdgeTpuContext* edgetpu_context)
{
  tflite::ops::builtin::BuiltinOpResolver resolver;
  resolver.AddCustom(edgetpu::kCustomOp, edgetpu::RegisterCustomOp());
  std::unique_ptr<tflite::Interpreter> interpreter;
  if (tflite::InterpreterBuilder(model, resolver)(&interpreter) != kTfLiteOk) {
    std::cerr << "Failed to build interpreter." << std::endl;
  }
  std::cout << "3.1\n";
  // Bind given context with interpreter.
  interpreter->SetExternalContext(kTfLiteEdgeTpuContext, edgetpu_context);
  std::cout << "3.2\n";
  interpreter->SetNumThreads(1);
  std::cout << "3.3\n";
  if (interpreter->AllocateTensors() != kTfLiteOk) {
    std::cerr << "Failed to allocate tensors." << std::endl;
  }
  return interpreter;
}
}//namespace

int main(int argc, char**argv)
{
    const std::string model_path = "/tmp/mobilenet_v1_1.0_224_quant_edgetpu.tflite";
    std::cout << "1...\n";
    std::unique_ptr<tflite::FlatBufferModel> model =
            tflite::FlatBufferModel::BuildFromFile(model_path.c_str());

    const auto& available_tpus = edgetpu::EdgeTpuManager::GetSingleton()->EnumerateEdgeTpu();
    std::cout << "available_tpus.size: " << available_tpus.size() << "\n"; // hopefully we'll see 1 here

    std::cout << "2\n";
    std::shared_ptr<edgetpu::EdgeTpuContext> edgetpu_context =
        edgetpu::EdgeTpuManager::GetSingleton()->OpenDevice();

    std::cout << "3\n";
    std::unique_ptr<tflite::Interpreter> model_interpreter =
        BuildEdgeTpuInterpreter(*model, edgetpu_context.get());

    std::cout << "Done\n";
    return 0;
}

Now I didn't use the bazel build, but made my own CMakeLists.txt.

#mkdir buildPi
#cd buildPi
#cmake -DCMAKE_TOOLCHAIN_FILE=/home/dev/oosman/pi/Toolchain-RaspberryPi.cmake ../
#make VERBOSE=1 -j8
#https://www.pyimagesearch.com/2019/04/22/getting-started-with-google-corals-tpu-usb-accelerator/
#on raspi0: sudo apt-get install python3-edgetpu
#https://coral.ai/models/

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)

set(PROJ minimal)
PROJECT(${PROJ})

set(CMAKE_C_FLAGS "-Wall -pthread")
set(CMAKE_C_FLAGS_DEBUG "-g -O0")
set(CMAKE_C_FLAGS_RELEASE "-O3")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++14 -lstdc++") #c++17 does not work with absl
set(CMAKE_CXX_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG})
set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE})
set(CMAKE_BUILD_TYPE Debug)

set(TFLITE_ENABLE_XNNPACK OFF)
set(CMAKE_SYSTEM_PROCESSOR "armv6")
set(TENSORFLOW_DIR "${CMAKE_SOURCE_DIR}/../tensorflow")

add_definitions(-DDARWINN_PORT_USE_EXTERNAL=1)
include_directories(
    ${CMAKE_SOURCE_DIR}/
    ${CMAKE_SOURCE_DIR}/include
    ${CMAKE_SOURCE_DIR}/bazel-build
    ${TENSORFLOW_DIR}/
    ${TENSORFLOW_DIR}/tensorflow/
    ${TENSORFLOW_DIR}/tensorflow/lite/
    ${TENSORFLOW_DIR}/tensorflow/lite/tools/optimize/
    ${CMAKE_BINARY_DIR}/tensorflow/src/tf/
    ${CMAKE_BINARY_DIR}/tensorflow/src/tf/tensorflow/lite/tools/make/downloads/flatbuffers/include/
    ${CMAKE_SOURCE_DIR}/googletest/googletest/include
    ${CMAKE_SOURCE_DIR}/googletest/googlemock/include
    ${CMAKE_BINARY_DIR}/glog_install/include
    )
link_directories(
    ${CMAKE_BINARY_DIR}
    ${CMAKE_SOURCE_DIR}/../libusb/buildpi
    /home/dev/oosman/pi/x-tools/arm-rpi-linux-gnueabihf/arm-rpi-linux-gnueabihf/sysroot/usr/lib/
    )
add_subdirectory(tensorflow/tensorflow/lite)
add_library(edgetpu
    ./api/allocated_buffer.cc
    ./api/layer_information.cc
    ./api/tensor_util.cc
    ./api/driver_factory.cc
    ./api/buffer.cc
    ./api/driver_options_helper.cc
    ./api/watchdog.cc
    ./driver_shared/time_stamper/driver_time_stamper.cc
    ./tflite/custom_op_user_data_direct.cc
    ./tflite/custom_op_data.cc
    ./tflite/edgetpu_manager_direct.cc
    ./tflite/edgetpu_c.cc
    ./tflite/edgetpu_delegate_for_custom_op.cc
    ./tflite/edgetpu_context_direct.cc
    ./tflite/custom_op_direct.cc
    ./tflite/edgetpu_context_factory.cc
    ./tflite/custom_op.cc
    ./tflite/edgetpu_delegate_for_custom_op_tflite_plugin.cc
    ./driver/mmio_driver.cc
    ./driver/memory/mmio_address_space.cc
    ./driver/memory/dual_address_space.cc
    ./driver/memory/buddy_allocator.cc
    ./driver/memory/mmu_mapper.cc
    ./driver/memory/buddy_address_space.cc
#    ./driver/memory/fake_dram_allocator.cc
#    ./driver/memory/fake_mmu_mapper.cc
    ./driver/memory/nop_address_space.cc
    ./driver/request.cc
    ./driver/instruction_buffers.cc
    ./driver/mmio/coherent_allocator.cc
    ./driver/device_buffer.cc
    ./driver/executable_util.cc
    ./driver/aligned_allocator.cc
    ./driver/registers/socket_registers.cc
    ./driver/registers/registers.cc
    ./driver/package_verifier.cc
    ./driver/beagle/beagle_top_level_handler.cc
    ./driver/beagle/beagle_pci_driver_provider.cc
    ./driver/beagle/beagle_pci_driver_provider_linux.cc
#    ./driver/beagle/beagle_pci_driver_provider_windows.cc
    ./driver/beagle/beagle_usb_driver_provider.cc
    ./driver/beagle/beagle_kernel_top_level_handler.cc
    ./driver/beagle/beagle_top_level_interrupt_manager.cc
    ./driver/kernel/kernel_interrupt_handler.cc
    ./driver/kernel/kernel_mmu_mapper.cc
    ./driver/kernel/kernel_coherent_allocator.cc
    ./driver/kernel/kernel_registers.cc
    ./driver/kernel/kernel_event_handler.cc
#    ./driver/kernel/windows/kernel_event_handler_windows.cc
#    ./driver/kernel/windows/kernel_registers_windows.cc
#    ./driver/kernel/windows/kernel_event_windows.cc
#    ./driver/kernel/windows/kernel_coherent_allocator_windows.cc
    ./driver/kernel/kernel_wire_interrupt_handler.cc
    ./driver/kernel/linux/kernel_registers_linux.cc
    ./driver/kernel/linux/kernel_event_linux.cc
    ./driver/kernel/linux/kernel_event_handler_linux.cc
    ./driver/kernel/linux/kernel_coherent_allocator_linux.cc
    ./driver/interrupt/interrupt_controller.cc
    ./driver/interrupt/top_level_interrupt_manager.cc
    ./driver/interrupt/wire_interrupt_handler.cc
    ./driver/interrupt/grouped_interrupt_controller.cc
    ./driver/dma_info.cc
    ./driver/driver_factory.cc
    ./driver/single_queue_dma_scheduler.cc
    ./driver/scalar_core_controller.cc
    ./driver/dma_info_extractor.cc
    ./driver/single_tpu_request.cc
    ./driver/device_buffer_mapper.cc
    ./driver/driver_factory_default.cc
    ./driver/run_controller.cc
    ./driver/driver.cc
##    ./driver/driver_helper.cc
    ./driver/dma_chunker.cc
    ./driver/package_registry.cc
    ./driver/usb/usb_io_request.cc
    ./driver/usb/libusb_options_default.cc
#    ./driver/usb/libusb_options_windows.cc
    ./driver/usb/local_usb_device.cc
    ./driver/usb/usb_dfu_commands.cc
    ./driver/usb/usb_standard_commands.cc
    ./driver/usb/usb_driver.cc
    ./driver/usb/usb_dfu_util.cc
    ./driver/usb/usb_registers.cc
    ./driver/usb/usb_ml_commands.cc
    ./driver/driver_factory_darwin.cc
    ./driver/allocator.cc
    ./driver/real_time_dma_scheduler.cc
#    ./driver/driver_factory_windows.cc
#    ./port/fileio_windows.cc
    ./port/timer_darwin.cc
#    ./port/timer_windows.cc
    ./port/posix_time.cc
    ./port/blocking_counter.cc
    ./port/shared_mutex.cc
    ./port/default/status_macros.cc
##    ./port/default/builddata.cc
    ./port/default/port_from_tf/status.cc
    ./port/default/port_from_tf/statusor.cc
    ./port/default/port_from_tf/logging.cc
    ./port/default/stringprintf.cc
    ./port/timer_linux.cc
    )
target_link_libraries(edgetpu
    tensorflow-lite
    )


add_executable(minimal
    main.cc
)


target_link_libraries(minimal
    dl
    edgetpu
    tensorflow-lite
    usb
    udev
)

I noticed that it calls into

provider->Enumerate();

which is a pure virtual function. Two subclasses exist but none of their Enumerate methods are getting called:

BeagleUsbDriverProvider::Enumerate()
BeaglePciDriverProvider::Enumerate()

I believe BeagleUsbDriverProvider::Enumerate() should get called. But then there is nothing instantiating a BeagleUsbDriverProvider object.

What am I missing here?


Solution

  • I figured out the answer, it was pretty stupid, the library has to be built as a shared library:

    add_library(edgetpu SHARED
    ...
    

    After that I got some linker errors and fixed them by adding the paths of so files, and it worked!