added my Recipes
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
SUMMARY = "Hand writing character recognition launcher based on HCR Neural Network"
|
||||
|
||||
LICENSE = "GPL-2.0-only & BSD-3-Clause"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
|
||||
|
||||
DEPENDS = "gtk+3 gstreamer1.0-plugins-base demo-launcher"
|
||||
DEPENDS:append:stm32mpcommon = " m4projects-stm32mp1 "
|
||||
|
||||
inherit pkgconfig
|
||||
|
||||
SRC_URI = " file://ai_char_reco_launcher.c \
|
||||
file://apps_launcher_example.sh \
|
||||
file://copro.c \
|
||||
file://copro.h \
|
||||
file://Makefile \
|
||||
file://timer.c \
|
||||
file://timer.h \
|
||||
\
|
||||
file://media \
|
||||
\
|
||||
file://demo \
|
||||
"
|
||||
|
||||
PV = "2.1"
|
||||
|
||||
S = "${WORKDIR}"
|
||||
|
||||
do_configure[noexec] = "1"
|
||||
|
||||
#Provides the firmware location for DK2 and EV1 boards
|
||||
EXTRA_OEMAKE = 'FIRMWARE_PATH_DK2="${STM32MP_USERFS_MOUNTPOINT}/Cube-M4-examples/STM32MP157C-DK2/Demonstrations/AI_Character_Recognition/lib/firmware"'
|
||||
EXTRA_OEMAKE += 'FIRMWARE_PATH_EV1="${STM32MP_USERFS_MOUNTPOINT}/Cube-M4-examples/STM32MP157C-EV1/Demonstrations/AI_Character_Recognition/lib/firmware"'
|
||||
|
||||
#Provides the firmware name
|
||||
EXTRA_OEMAKE += 'FIRMWARE_NAME="AI_Character_Recognition.elf"'
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${prefix}/local/demo/bin/
|
||||
install -d ${D}${prefix}/local/demo/media/
|
||||
install -d ${D}${prefix}/local/demo/application/m4_ai/bin
|
||||
install -d ${D}${prefix}/local/demo/application/m4_ai/pictures
|
||||
|
||||
install -m 0755 ${B}/ai_char_reco_launcher ${D}${prefix}/local/demo/bin/
|
||||
install -m 0755 ${B}/apps_launcher_example.sh ${D}${prefix}/local/demo/bin/
|
||||
install -m 0644 ${B}/media/* ${D}${prefix}/local/demo/media/
|
||||
install -m 0755 -D ${WORKDIR}/demo/application/m4_ai/bin/* ${D}${prefix}/local/demo/application/m4_ai/bin/
|
||||
install -m 0755 -D ${WORKDIR}/demo/application/m4_ai/pictures/* ${D}${prefix}/local/demo/application/m4_ai/pictures/
|
||||
install -m 0644 -D ${WORKDIR}/demo/application/*.yaml ${D}${prefix}/local/demo/application/
|
||||
}
|
||||
|
||||
FILES:${PN} += "${prefix}/local/demo/"
|
||||
RDEPENDS:${PN} += "gtk+3 gstreamer1.0-plugins-base demo-launcher"
|
||||
RDEPENDS:${PN}:append:stm32mpcommon = " m4projects-stm32mp1-userfs "
|
||||
@@ -0,0 +1,15 @@
|
||||
FIRMWARE_PATH_DK2?="/usr/local/Cube-M4-examples/STM32MP157C-DK2/Demonstrations/AI_Character_Recognition/lib/firmware"
|
||||
FIRMWARE_PATH_EV1?="/usr/local/Cube-M4-examples/STM32MP157C-EV1/Demonstrations/AI_Character_Recognition/lib/firmware"
|
||||
FIRMWARE_NAME?="AI_Character_Recognition.elf"
|
||||
|
||||
|
||||
# support GTK
|
||||
CFLAGS += -Wall $(shell pkg-config --cflags gtk+-3.0)
|
||||
LDFLAGS += $(shell pkg-config --libs gtk+-3.0)
|
||||
|
||||
all: ai_char_reco_launcher
|
||||
|
||||
ai_char_reco_launcher: copro.c timer.c ai_char_reco_launcher.c
|
||||
$(CC) -DFIRMWARE_PATH_DK2='"${FIRMWARE_PATH_DK2}"' -DFIRMWARE_PATH_EV1='"${FIRMWARE_PATH_EV1}"' -DFIRMWARE_NAME='"${FIRMWARE_NAME}"' -o $@ $^ $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
clean: ; rm -rf *.o ai_char_reco_launcher
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,66 @@
|
||||
#!/bin/sh
|
||||
|
||||
video() {
|
||||
echo "Launch video"
|
||||
gst-launch-1.0 playbin uri=file:///usr/local/demo/media/Teaser-STM32MP1.webm video-sink="waylandsink sync=false" audio-sink="fakesink" &
|
||||
}
|
||||
|
||||
audio() {
|
||||
echo "Launch audio"
|
||||
gst-launch-1.0 playbin uri=file:///usr/local/demo/media/ST12266_269_full_technology-freaks_0160.ogg &
|
||||
}
|
||||
|
||||
picture() {
|
||||
echo "Display picture"
|
||||
gst-launch-1.0 filesrc location=/usr/local/demo/media/stm32cubeai.png ! pngdec ! videoconvert ! imagefreeze ! glimagesink &
|
||||
}
|
||||
|
||||
camera() {
|
||||
echo "Launch preview camera"
|
||||
v4l2-ctl --set-parm=20
|
||||
gst-launch-1.0 v4l2src ! "video/x-raw, format=YUY2, width=320, height=240" ! waylandsink &
|
||||
}
|
||||
|
||||
kill_all() {
|
||||
echo "kill previous app"
|
||||
killall gst-launch-1.0
|
||||
}
|
||||
|
||||
quit() {
|
||||
kill_all
|
||||
killall ai_char_reco_launcher
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
V)
|
||||
video
|
||||
;;
|
||||
S)
|
||||
kill_all
|
||||
;;
|
||||
A)
|
||||
audio
|
||||
;;
|
||||
P)
|
||||
picture
|
||||
;;
|
||||
C)
|
||||
camera
|
||||
;;
|
||||
Q)
|
||||
quit
|
||||
;;
|
||||
*)
|
||||
echo "HELP: $0 [command]"
|
||||
echo "available commands:"
|
||||
echo " V (launch video)"
|
||||
echo " A (Launch audio)"
|
||||
echo " P (Display picture)"
|
||||
echo " C (Launch preview camera)"
|
||||
echo " S (kill previous app)"
|
||||
echo " Q (quit the launcher)"
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* copro.c
|
||||
* Implements Copro's abstraction layer
|
||||
*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
|
||||
*
|
||||
* License type: GPLv2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "copro.h"
|
||||
|
||||
#define MAX_BUF 80
|
||||
|
||||
/* The file descriptor used to manage our TTY over RPMSG */
|
||||
static int mFdRpmsg = -1;
|
||||
|
||||
int copro_isFwRunning(void)
|
||||
{
|
||||
int fd;
|
||||
size_t byte_read;
|
||||
int result = 0;
|
||||
unsigned char bufRead[MAX_BUF];
|
||||
char *user = getenv("USER");
|
||||
if (user && strncmp(user, "root", 4)) {
|
||||
system("XTERM=xterm su root -c 'cat /sys/class/remoteproc/remoteproc0/state' > /tmp/remoteproc0_state");
|
||||
fd = open("/tmp/remoteproc0_state", O_RDONLY);
|
||||
} else {
|
||||
fd = open("/sys/class/remoteproc/remoteproc0/state", O_RDONLY);
|
||||
}
|
||||
if (fd < 0) {
|
||||
printf("Error opening remoteproc0/state, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
byte_read = (size_t) read (fd, bufRead, MAX_BUF);
|
||||
if (byte_read >= strlen("running")) {
|
||||
char* pos = strstr((char*)bufRead, "running");
|
||||
if(pos) {
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
int copro_stopFw(void)
|
||||
{
|
||||
int fd;
|
||||
char *user = getenv("USER");
|
||||
if (user && strncmp(user, "root",4)) {
|
||||
system("su root -c 'echo stop > /sys/class/remoteproc/remoteproc0/state'");
|
||||
return 0;
|
||||
}
|
||||
fd = open("/sys/class/remoteproc/remoteproc0/state", O_RDWR);
|
||||
if (fd < 0) {
|
||||
printf("Error opening remoteproc0/state, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
write(fd, "stop", strlen("stop"));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copro_startFw(void)
|
||||
{
|
||||
int fd;
|
||||
char *user = getenv("USER");
|
||||
if (user && strncmp(user, "root",4)) {
|
||||
system("su root -c 'echo start > /sys/class/remoteproc/remoteproc0/state'");
|
||||
return 0;
|
||||
}
|
||||
fd = open("/sys/class/remoteproc/remoteproc0/state", O_RDWR);
|
||||
if (fd < 0) {
|
||||
printf("Error opening remoteproc0/state, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
write(fd, "start", strlen("start"));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copro_getFwPath(char* pathStr)
|
||||
{
|
||||
int fd;
|
||||
int byte_read;
|
||||
char *user = getenv("USER");
|
||||
if (user && strncmp(user, "root",4)) {
|
||||
system("XTERM=xterm su root -c 'cat /sys/module/firmware_class/parameters/path' > /tmp/parameters_path");
|
||||
fd = open("/tmp/parameters_path", O_RDONLY);
|
||||
} else {
|
||||
fd = open("/sys/module/firmware_class/parameters/path", O_RDONLY);
|
||||
}
|
||||
if (fd < 0) {
|
||||
printf("Error opening firmware_class/parameters/path, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
byte_read = read (fd, pathStr, MAX_BUF);
|
||||
close(fd);
|
||||
return byte_read;
|
||||
}
|
||||
|
||||
int copro_setFwPath(char* pathStr)
|
||||
{
|
||||
int fd;
|
||||
int result = 0;
|
||||
char *user = getenv("USER");
|
||||
if (user && strncmp(user, "root",4)) {
|
||||
char cmd[1024];
|
||||
snprintf(cmd, 1024, "su root -c 'echo %s > /sys/module/firmware_class/parameters/path'", pathStr);
|
||||
system(cmd);
|
||||
return strlen(pathStr);
|
||||
}
|
||||
fd = open("/sys/module/firmware_class/parameters/path", O_RDWR);
|
||||
if (fd < 0) {
|
||||
printf("Error opening firmware_class/parameters/path, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
result = write(fd, pathStr, strlen(pathStr));
|
||||
close(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
int copro_getFwName(char* name)
|
||||
{
|
||||
int fd;
|
||||
int byte_read;
|
||||
char *user = getenv("USER");
|
||||
if (user && strncmp(user, "root",4)) {
|
||||
system("XTERM=xterm su root -c 'cat /sys/class/remoteproc/remoteproc0/firmware' > /tmp/remoteproc0_firmware");
|
||||
fd = open("/tmp/remoteproc0_firmware", O_RDONLY);
|
||||
} else {
|
||||
fd = open("/sys/class/remoteproc/remoteproc0/firmware", O_RDWR);
|
||||
}
|
||||
if (fd < 0) {
|
||||
printf("Error opening remoteproc0/firmware, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
byte_read = read (fd, name, MAX_BUF);
|
||||
close(fd);
|
||||
/* remove \n from the read character */
|
||||
return byte_read - 1;
|
||||
}
|
||||
|
||||
int copro_setFwName(char* nameStr)
|
||||
{
|
||||
int fd;
|
||||
int result = 0;
|
||||
char *user = getenv("USER");
|
||||
if (user && strncmp(user, "root",4)) {
|
||||
char cmd[1024];
|
||||
snprintf(cmd, 1024, "su root -c 'echo %s > /sys/class/remoteproc/remoteproc0/firmware'", nameStr);
|
||||
system(cmd);
|
||||
return strlen(nameStr);
|
||||
}
|
||||
fd = open("/sys/class/remoteproc/remoteproc0/firmware", O_RDWR);
|
||||
if (fd < 0) {
|
||||
printf("Error opening remoteproc0/firmware, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
result = write(fd, nameStr, strlen(nameStr));
|
||||
close(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
int copro_openTtyRpmsg(int modeRaw)
|
||||
{
|
||||
struct termios tiorpmsg;
|
||||
mFdRpmsg = open("/dev/ttyRPMSG0", O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
if (mFdRpmsg < 0) {
|
||||
printf("Error opening ttyRPMSG0, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
/* get current port settings */
|
||||
tcgetattr(mFdRpmsg,&tiorpmsg);
|
||||
if (modeRaw) {
|
||||
tiorpmsg.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
|
||||
| INLCR | IGNCR | ICRNL | IXON);
|
||||
tiorpmsg.c_oflag &= ~OPOST;
|
||||
tiorpmsg.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||
tiorpmsg.c_cflag &= ~(CSIZE | PARENB);
|
||||
tiorpmsg.c_cflag |= CS8;
|
||||
} else {
|
||||
/* ECHO off, other bits unchanged */
|
||||
tiorpmsg.c_lflag &= ~ECHO;
|
||||
/*do not convert LF to CR LF */
|
||||
tiorpmsg.c_oflag &= ~ONLCR;
|
||||
}
|
||||
tcsetattr(mFdRpmsg, TCSANOW, &tiorpmsg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copro_closeTtyRpmsg(void)
|
||||
{
|
||||
close(mFdRpmsg);
|
||||
mFdRpmsg = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copro_writeTtyRpmsg(int len, char* pData)
|
||||
{
|
||||
int result = 0;
|
||||
if (mFdRpmsg < 0) {
|
||||
printf("Error writing ttyRPMSG0, fileDescriptor is not set\n");
|
||||
return mFdRpmsg;
|
||||
}
|
||||
result = write(mFdRpmsg, pData, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
int copro_readTtyRpmsg(int len, char* pData)
|
||||
{
|
||||
int byte_rd, byte_avail;
|
||||
int result = 0;
|
||||
if (mFdRpmsg < 0) {
|
||||
printf("Error reading ttyRPMSG0, fileDescriptor is not set\n");
|
||||
return mFdRpmsg;
|
||||
}
|
||||
ioctl(mFdRpmsg, FIONREAD, &byte_avail);
|
||||
if (byte_avail > 0) {
|
||||
if (byte_avail >= len) {
|
||||
byte_rd = read (mFdRpmsg, pData, len);
|
||||
} else {
|
||||
byte_rd = read (mFdRpmsg, pData, byte_avail);
|
||||
}
|
||||
/*printf("copro_readTtyRpmsg, read successfully %d bytes to %p, [0]=0x%x\n", byte_rd, pData, pData[0]);*/
|
||||
result = byte_rd;
|
||||
} else {
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
char copro_computeCRC(char *bb, int size)
|
||||
{
|
||||
short sum = 0;
|
||||
|
||||
for (int i = 0; i < size - 1; i++)
|
||||
sum += (bb[i] & 0xFF);
|
||||
|
||||
char res = (char) (sum & 0xFF);
|
||||
res += (char) (sum >> 8);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* copro.h
|
||||
* Implements Copro's abstraction layer
|
||||
*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
|
||||
*
|
||||
* License type: GPLv2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __COPRO_H__
|
||||
#define __COPRO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
int copro_isFwRunning(void);
|
||||
int copro_stopFw(void);
|
||||
int copro_startFw(void);
|
||||
int copro_getFwPath(char* pathStr);
|
||||
int copro_setFwPath(char* pathStr);
|
||||
int copro_getFwName(char* pathStr);
|
||||
int copro_setFwName(char* nameStr);
|
||||
int copro_openTtyRpmsg(int modeRaw);
|
||||
int copro_closeTtyRpmsg(void);
|
||||
int copro_writeTtyRpmsg(int len, char* pData);
|
||||
int copro_readTtyRpmsg(int len, char* pData);
|
||||
char copro_computeCRC(char *bb, int size);
|
||||
|
||||
#endif /* __COPRO_H__ */
|
||||
@@ -0,0 +1,14 @@
|
||||
Application:
|
||||
Name: Artificial
|
||||
Description: Intelligence
|
||||
Icon: application/m4_ai/pictures/ST7079_AI_neural_pink.png
|
||||
Type: script
|
||||
Board:
|
||||
List: stm32mp15
|
||||
Script:
|
||||
Start: application/m4_ai/bin/launch_AI.sh
|
||||
Action:
|
||||
button_release_event: script_start
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
script -qc "/usr/local/demo/bin/ai_char_reco_launcher /usr/local/demo/bin/apps_launcher_example.sh"
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
*************************************************************************************************
|
||||
* @file readme.txt
|
||||
* @author MCD Application Team
|
||||
* @brief Description of the Artificial Intelligence Hand Writing Character Recognition example.
|
||||
*************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2019 STMicroelectronics. All rights reserved.
|
||||
*
|
||||
* This software component is licensed by ST under BSD 3-Clause license,
|
||||
* the "License"; You may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
* opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
*************************************************************************************************
|
||||
*/
|
||||
|
||||
This project demonstrate a complex application that is running on both CPU1(CA7) and CPU2(CM4).
|
||||
The application is a launcher that recognize hand writing character drawn on the touch screen in order
|
||||
to execute specific actions.
|
||||
|
||||
CPU1 (CA7) control the touch event and the Graphic User Interface.
|
||||
CPU2 (CM4) is used to offload the processing of a Cube.AI pre-build Neural Network.
|
||||
|
||||
The communication between the CPU1(CA7) and the CPU2(CM4) is done through a Virtual UART to create an
|
||||
Inter-Processor Communication channel seen as a TTY device in Linux.
|
||||
The implementation is based on:
|
||||
* RPMSG framework on CPU1(CA7) side
|
||||
* and OpenAMP MW on the CPU2(CM4) side
|
||||
|
||||
OpenAMP MW uses the following HW resources
|
||||
* IPCC peripheral for event signal (mailbox) between CPU1(CA7) and CPU2(CM4)
|
||||
* MCUSRAM peripheral for buffer communications (virtio buffers) between CPU1(CA7) and CPU2(CM4)
|
||||
Reserved shared memeory region for this example: SHM_ADDR=0x10040000 and SHM_SIZE=128k.
|
||||
It is defined in platform_info.c file
|
||||
|
||||
A communication protocol has been defined between the CPU1(CA7 and the CPU2(CM4).
|
||||
The data frames exchanged have the follwowing structure:
|
||||
----------------------------------------------------------------
|
||||
| msg ID | data Length | data Byte 1 | ... | data Byte n | CRC |
|
||||
----------------------------------------------------------------
|
||||
|
||||
- 3 types of message could be received by CPU2(CM4):
|
||||
* Set the Neural Network input type (0x20, 0x01, data, CRC)
|
||||
* data = 0 => NN input is letter or digit
|
||||
* data = 1 => NN input is letter only
|
||||
* data = 2 => NN input is digit only
|
||||
|
||||
* Provide the touch screen coordinate (0x20, n, data_x1, data_y1, ... , data_xn, data_yn, CRC)
|
||||
* n => the number of coordinate points
|
||||
* data_xn => x coordinate of the point n
|
||||
* data_yn => y coordinate of the point n
|
||||
|
||||
* Start ai nn processing (0x22, 0x00, CRC)
|
||||
|
||||
- 4 types of acknowledges could be received on CPU1(CA7) side:
|
||||
* Bad acknowledge (0xFF, 0x00, CRC)
|
||||
|
||||
* Good acknowledge (0xF0, 0x00, CRC)
|
||||
|
||||
* Touch screen acknowledge (0xF0, 0x01, n, CRC)
|
||||
* n => number of screen coordinate points acknowledged
|
||||
|
||||
* AI processing result acknowledge (0xF0, 0x04, char, accuracy, time_1, time_2, CRC)
|
||||
* char => this is the recognized letter (or digit)
|
||||
* accuracy => this is the confidence expressed in percentage
|
||||
* time_1 => upper Bytes of the time (word) expressed in ms
|
||||
* time_2 => lower Bytes of the time (word) expressed in ms
|
||||
|
||||
On CPU2(CM4) side:
|
||||
- CPU2(CM4) initialize OPenAMP MW which initializes/configures IPCC peripheral through HAL
|
||||
and setup openamp-rpmsg framwork infrastructure
|
||||
- CPU2(CM4) creates 1 rpmsg channels for 1 virtual UART instance UART0
|
||||
- CPU2(CM4) initialize the Character Recognition Neural Network
|
||||
- CPU2(CM4) is waiting for messages from CPU1(CA7) on this channels
|
||||
- When CPU2(CM4) receives a message on 1 Virtual UART instance/rpmsg channel, it processes the message
|
||||
to execute the associated action:
|
||||
* set the NN input type to the desire value
|
||||
* or register the touch event coordinate to generate the picture that will be processed by the NN
|
||||
* or start the NN processing and wait for the results
|
||||
- On every previous action, the CPU(CM4) is sending back to the CPU1(CA7) and acknowledge already defined
|
||||
above.
|
||||
|
||||
On CPU1(CA7) side:
|
||||
- CPU1(CA7) open the input event to register the touch events generated by the user's finger drawing
|
||||
- CPU1(CA7) configure the input type (Letter only) of the Neural Network running on the CPU2(CM4) by
|
||||
sending a message throught the virtual TTY communication channel
|
||||
- when the drawing is finished, CPU1(CA7) process the touch event data and send it to the CPU2(CM4)
|
||||
- CPU1(CA7) start the Neural Network processing wait for the result and display the recognized character on
|
||||
the diplay
|
||||
|
||||
Some information about the Character Recognition Neural Network:
|
||||
The Character Recognition Neural Network used is a Keras model processed by Cube.AI to generate the executable
|
||||
that can be run on the CPU2(CM4).
|
||||
The Keras model used is located in the root directory of this project:
|
||||
model-ABC123-112.h5
|
||||
This model has been used in Cube.AI to generate the Neural Network binary.
|
||||
The model accept as input a 28x28 picture encoded with float in black and white (black = 0.0 or White = 1.0).
|
||||
The output layer of the Neural Network contains 36 neurons (A -> Z and 0 -> 9).
|
||||
|
||||
Notes:
|
||||
- It requires Linux console to run the application.
|
||||
- CM4 logging is redirected in Shared memory in MCUSRAM and can be displayed using following command:
|
||||
cat /sys/kernel/debug/remoteproc/remoteproc0/trace0
|
||||
|
||||
Following command should be done in Linux console on CA7 to run the example :
|
||||
> /usr/local/demo/bin/ai_char_reco_launcher /usr/local/demo/bin/apps_launcher_example.sh
|
||||
|
||||
You are ready to draw letter on the touch screen
|
||||
|
||||
Hardware and Software environment:
|
||||
- This example runs on STM32MP157CACx devices.
|
||||
- This example has been tested with STM32MP157C-DK2 and STM32MP157c-EVAL board and can be
|
||||
easily tailored to any other supported device and development board.
|
||||
|
||||
Where to find the M4 firmware source code:
|
||||
The M4 firmware source code is delivered as demonstration inside the STM32CubeMP1.
|
||||
For the DK2 board:
|
||||
<STM32CubeMP1>/Firmware/Projects/STM32MP157C-DK2/Demonstrations/AI_Character_Recognition
|
||||
For the EV1 board:
|
||||
<STM32CubeMP1>/Firmware/Projects/STM32MP157C-DK2/Demonstrations/AI_Character_Recognition
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* timer.c
|
||||
* Implements timer services
|
||||
*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
|
||||
*
|
||||
* License type: GPLv2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <pthread.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "timer.h"
|
||||
|
||||
#define MAX_TIMER_COUNT 1000
|
||||
|
||||
struct timer_node
|
||||
{
|
||||
int fd;
|
||||
timer_handler callback;
|
||||
void * user_data;
|
||||
unsigned int interval;
|
||||
struct timer_node * next;
|
||||
};
|
||||
|
||||
static void * _timer_thread(void * data);
|
||||
static pthread_t g_thread_id;
|
||||
static struct timer_node *g_head = NULL;
|
||||
|
||||
int timer_init()
|
||||
{
|
||||
if(pthread_create(&g_thread_id, NULL, _timer_thread, NULL))
|
||||
{
|
||||
/*Thread creation failed*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void timer_finalize()
|
||||
{
|
||||
while(g_head) timer_stop((size_t)g_head);
|
||||
|
||||
pthread_cancel(g_thread_id);
|
||||
pthread_join(g_thread_id, NULL);
|
||||
}
|
||||
|
||||
size_t timer_start(unsigned int interval,
|
||||
timer_handler handler,
|
||||
void * user_data)
|
||||
{
|
||||
struct timer_node * new_node = NULL;
|
||||
struct itimerspec new_value;
|
||||
|
||||
new_node = (struct timer_node *)malloc(sizeof(struct timer_node));
|
||||
|
||||
if(new_node == NULL) return 0;
|
||||
|
||||
new_node->callback = handler;
|
||||
new_node->user_data = user_data;
|
||||
new_node->interval = interval;
|
||||
|
||||
new_node->fd = timerfd_create(CLOCK_REALTIME, 0);
|
||||
|
||||
if (new_node->fd == -1)
|
||||
{
|
||||
free(new_node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_value.it_value.tv_sec = interval / 1000;
|
||||
new_value.it_value.tv_nsec = (interval % 1000) * 1000 * 1000;
|
||||
new_value.it_interval.tv_sec = 0;
|
||||
new_value.it_interval.tv_nsec = 0;
|
||||
|
||||
timerfd_settime(new_node->fd, 0, &new_value, NULL);
|
||||
|
||||
/*Inserting the timer node into the list*/
|
||||
new_node->next = g_head;
|
||||
g_head = new_node;
|
||||
|
||||
return (size_t)new_node;
|
||||
}
|
||||
|
||||
void timer_stop(size_t timer_id)
|
||||
{
|
||||
struct timer_node * tmp = NULL;
|
||||
struct timer_node * node = (struct timer_node *)timer_id;
|
||||
|
||||
if (node == NULL) return;
|
||||
|
||||
close(node->fd);
|
||||
|
||||
if(node == g_head)
|
||||
{
|
||||
g_head = g_head->next;
|
||||
}
|
||||
|
||||
tmp = g_head;
|
||||
|
||||
while(tmp && tmp->next != node) tmp = tmp->next;
|
||||
|
||||
if(tmp && tmp->next)
|
||||
{
|
||||
tmp->next = tmp->next->next;
|
||||
}
|
||||
|
||||
if(node) free(node);
|
||||
}
|
||||
|
||||
struct timer_node * _get_timer_from_fd(int fd)
|
||||
{
|
||||
struct timer_node * tmp = g_head;
|
||||
|
||||
while(tmp)
|
||||
{
|
||||
if(tmp->fd == fd) return tmp;
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void * _timer_thread(void * data)
|
||||
{
|
||||
struct pollfd ufds[MAX_TIMER_COUNT] = {{0}};
|
||||
int iMaxCount = 0;
|
||||
struct timer_node * tmp = NULL;
|
||||
int read_fds = 0, i, s;
|
||||
uint64_t exp;
|
||||
|
||||
while(1)
|
||||
{
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
pthread_testcancel();
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
||||
|
||||
iMaxCount = 0;
|
||||
tmp = g_head;
|
||||
|
||||
memset(ufds, 0, sizeof(struct pollfd)*MAX_TIMER_COUNT);
|
||||
while(tmp)
|
||||
{
|
||||
ufds[iMaxCount].fd = tmp->fd;
|
||||
ufds[iMaxCount].events = POLLIN;
|
||||
iMaxCount++;
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
read_fds = poll(ufds, iMaxCount, 100);
|
||||
|
||||
if (read_fds <= 0) continue;
|
||||
|
||||
for (i = 0; i < iMaxCount; i++)
|
||||
{
|
||||
if (ufds[i].revents & POLLIN)
|
||||
{
|
||||
s = read(ufds[i].fd, &exp, sizeof(uint64_t));
|
||||
|
||||
if (s != sizeof(uint64_t)) continue;
|
||||
|
||||
tmp = _get_timer_from_fd(ufds[i].fd);
|
||||
|
||||
if(tmp && tmp->callback) tmp->callback((size_t)tmp, tmp->user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* timer.h
|
||||
* Implements timer services
|
||||
*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
|
||||
*
|
||||
* License type: GPLv2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TIMER_H
|
||||
#define __TIMER_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef void (*timer_handler)(size_t timer_id, void * user_data);
|
||||
|
||||
int timer_init();
|
||||
void timer_finalize();
|
||||
size_t timer_start(unsigned int interval, timer_handler handler, void * user_data);
|
||||
void timer_stop(size_t timer_id);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user