目次[非表示]
前回
前回のブログでは、TensorFlow Lite for microのサンプル(Hello world)をM5StickV向けにビルド、動作させるところまでを書いた。出力はコンソール出力だけで、M5StickVのLCDには何も表示しない。
目的
今回は、M5StickVのLCDに表示を行うところをメインにする。
こんな感じである。
参考
LCDに表示するまでの道のり
LCDに表示するにはHWの制御がかなり必要である。自前でやるのもよいが、今回はsipeedが提供するMaixPyに含まれるライブラリを使用することにする。
前回のプロジェクトに追加・変更する方針とする。

sipeed / MaixPyのMaixPyのSDK
もともと、Micropython 用の環境であるが、SDKと利用して独自のcプロジェクトをビルドすることができる。
ただ、C++はビルドできないため、SDKのみを利用することにした。
components配下のSDKの部分を利用する。以下のフォルダを利用した。
- boards
- drivers
- kendryte_sdk
- utils
sipeed/MaixPyのSDKをプロジェクトに追加
プロジェクトに追加する。
- sipeed/MaixPyのSDK(compoents配下)をlib(kendryte K210のStandard SDK)配下に配置。
- CMakeLists.txtにcompoentsを加えるように変更。
(Githubの差分はこちら)
sipeed/MaixPyのSDKをC++から呼び出せるように変更
sipeed/MaixPyのSDKはC++から呼び出すことを考慮していない箇所が多数ある。このため、使用する部分のヘッダを変更する。
extern "C" の追加し、呼び出し可能とする。
今回は以下のヘッダを修正。
TensorFlow lite for microのソース変更
以下の処理を追加する。
- main.ccでLCDを含むHWの初期化
- output_handler.ccで描画の更新
HWの初期化
src/micro/tensorflow/tensorflow/lite/micro/examples/hello_world/main.ccで行う。
- HWの初期化を行う。
m5stick_init()
(BUTTON B長押しの電源OFFもできるようになったりする) - setup_lcd()でLCD初期化を行う。
man.ccはこのような感じになる。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. | |
Licensed 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 "tensorflow/lite/micro/examples/hello_world/main_functions.h" | |
#include "m5stick.h" | |
#include "lcd.h" | |
#include "fpioa.h" | |
#include "global_config.h" | |
void setup_lcd(uint16_t fillColor, lcd_dir_t lcdDirection) | |
{ | |
fpioa_set_function(21, static_cast<_fpioa_function>(FUNC_GPIOHS0 + RST_GPIONUM)); | |
fpioa_set_function(20, static_cast<_fpioa_function>(FUNC_GPIOHS0 + DCX_GPIONUM)); | |
fpioa_set_function(22, static_cast<_fpioa_function>(FUNC_SPI0_SS0 + LCD_SPI_SLAVE_SELECT)); | |
fpioa_set_function(19, FUNC_SPI0_SCLK); | |
fpioa_set_function(18, FUNC_SPI0_D0); | |
lcd_init(CONFIG_LCD_DEFAULT_FREQ, false, 52, 40, 40, 52, true, CONFIG_LCD_DEFAULT_WIDTH, CONFIG_LCD_DEFAULT_HEIGHT); | |
lcd_set_direction(lcdDirection); | |
lcd_clear(fillColor); | |
} | |
// This is the default main used on systems that have the standard C entry | |
// point. Other devices (for example FreeRTOS or ESP32) that have different | |
// requirements for entry code (like an app_main function) should specialize | |
// this main.cc file in a target-specific subfolder. | |
int main(int argc, char* argv[]) { | |
m5stick_init(); | |
setup_lcd(BLACK, DIR_YX_LRUD); | |
setup(); | |
while (true) { | |
loop(); | |
} | |
} |
出力値に応じた点の描画
STM32F746の実装を参考。LCD出力用の関数をsipeed/MaixPyのSDKを使用する。ただ、元の実装では円を描画しているが、sipeed/MaixPyのSDKには用意されていない。今回は矩形描画で代替えした。
使用した関数は以下。
- lcd_get_width ... LCDの幅を取得
- lcd_get_height ... LCDの高さを取得
- lcd_clear ... LCDのクリア
- lcd_fill_rectangle ... 矩形を描画
output_handler.ccはこのような感じになる。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. | |
Licensed 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 "tensorflow/lite/micro/examples/hello_world/output_handler.h" | |
#include "tensorflow/lite/micro/examples/hello_world/constants.h" | |
#include "lcd.h" | |
// The colors we'll draw | |
const uint16_t background_color = BLACK; // Red | |
const uint16_t foreground_color = RED; // Red | |
// The size of the dot we'll draw | |
const int dot_radius = 3; | |
// Track whether the function has run at least once | |
bool initialized = false; | |
// Size of the drawable area | |
int width; | |
int height; | |
// Midpoint of the y axis | |
int midpoint; | |
// Pixels per unit of x_value | |
int x_increment; | |
void HandleOutput(tflite::ErrorReporter* error_reporter, float x_value, | |
float y_value) { | |
// Do this only once | |
if (!initialized) { | |
// Calculate the drawable area to avoid drawing off the edges | |
width = (int)lcd_get_width() - (dot_radius * 2); | |
height = (int)lcd_get_height() - (dot_radius * 2); | |
// Calculate the y axis midpoint | |
midpoint = height / 2; | |
// Calculate fractional pixels per unit of x_value | |
x_increment = static_cast<float>(width) / kXrange; | |
initialized = true; | |
} | |
// Log the current X and Y values | |
error_reporter->Report("x_value: %f, y_value: %f\n", x_value, y_value); | |
// Clear the previous drawing | |
lcd_clear(background_color); | |
// Calculate x position, ensuring the dot is not partially offscreen, | |
// which causes artifacts and crashes | |
int x_pos = dot_radius + static_cast<int>(x_value * x_increment); | |
// Calculate y position, ensuring the dot is not partially offscreen | |
int y_pos; | |
if (y_value >= 0) { | |
// Since the display's y runs from the top down, invert y_value | |
y_pos = dot_radius + static_cast<int>(midpoint * (1.f - y_value)); | |
} else { | |
// For any negative y_value, start drawing from the midpoint | |
y_pos = | |
dot_radius + midpoint + static_cast<int>(midpoint * (0.f - y_value)); | |
} | |
// Draw the dot | |
lcd_fill_rectangle(x_pos - dot_radius, y_pos - dot_radius, | |
x_pos + dot_radius, y_pos + dot_radius, | |
foreground_color); | |
} |
最後に
前回、今回とM5StickVでTensorFlow Lite for microのサンプルをビルドするやり方を記載した。M5StickVには6軸センサやカメラがあるので、他のサンプルも行けると思うのでチャレンジしてみたい。
0 件のコメント:
コメントを投稿