Hanjie's Blog

一只有理想的羊驼


  • Home

  • Categories

  • Archives

  • Tags

  • About

  • Search
close

AR眼镜虚实结合标定结果

Posted on 2021-08-19   |   In Tech , AR   |  

AR系统中存在虚拟影像空间和现实世界空间两个空间。在实际使用中,我们要求虚拟影像空间与现实世界空间能够对齐,使得虚拟物体与实际物体能够正确地叠加在一起。这需要我们对AR眼镜进行标定,获得传感器与光学屏幕,人眼之间的几何关系[1]。

ar_glasses_calibration1


  1. Cutolo, F., Fontana, U., Cattari, N. and Ferrari, V., 2020. Off-line camera-based calibration for optical see-through head-mounted displays. Applied Sciences, 10(1), p.193. ↩

Unity Android App获取root权限

Posted on 2021-08-19   |   In Tech , AR   |  

手机已经通过使用Magisk为App提供超级用户的权限,但是需要App主动向系统索求权限。下面我们通过使用一个Java Jar包,使得Unity生成的Android App能够获得root权限。

系统:Ubuntu Unity: 2020.3.13f1 Android Studio 3.6.1

首先,Android Studio中,菜单栏选择File->New->NewProject创建一个Empty Activity项目,Package name和Minimum SDK与Unity中的一致:

android_unity_root1

android_unity_root2

在菜单栏选择File->Project Structure->Modules->New Module,新建一个Android Library[1],我们命名为GetRoot。注意Package name和Minimum SDK与Unity中的一致:

android_unity_root3

将/home/luohanjie/Unity/Hub/Editor/2019.4.15f1/Editor/Data/PlaybackEngines/AndroidPlayer/Variations/il2cpp/Development/Classes下的classes.jar复制到Android项目Module文件下的libs文件夹下,如/home/luohanjie/Documents/Android Projects/Unity2Android/getroot/libs。

将/home/luohanjie/Unity/Hub/Editor/2019.4.15f1/Editor/Data/PlaybackEngines/AndroidPlayer/Source/com/unity3d下的UnityPlayerActivity.java复制到Android Studio中,Project栏目下Module name/src/main/java/Package name下:

android_unity_root4

Android Studio中,Project栏目下Module name/src/main/java/Package name新建一个Empty Activity:

android_unity_root5

android_unity_root6

修改MainActivity.java[2]:

package com.cvte.imagetracker;

import android.os.Bundle;

import java.io.DataOutputStream;

public class MainActivity extends UnityPlayerActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

public void GetRoot() {
try {
//通过执行su产生一个具有root权限的进程
Process p = Runtime.getRuntime().exec("su");
//然后,在向这个进程的写入要执行的命令,即可达到以root权限执行命令:
DataOutputStream dos = new DataOutputStream(p.getOutputStream());
dos.writeBytes( "\n");//cmd命令可为空
dos.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}

通过Android Studio中Project栏目下Module name/src/main/下打开AndroidManifest.xml文件并且修改,注意package和android:name的参数:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cvte.imagetracker">


<application>
<!-- 这个android:name的值必须为包名+类名-->
<activity android:name="com.cvte.imagetracker.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<!-- 这一行不能少,否则会闪退-->
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
</application>

</manifest>

通过Android Studio中Project栏目下Module name下打开build.gradle文件,修改minSdkVersion和targetSdkVersion,并在后面添加exportJar代码[1]:

apply plugin: 'com.android.library'

android {
compileSdkVersion 30
buildToolsVersion "30.0.2"

defaultConfig {
minSdkVersion 27
targetSdkVersion 27
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}

}

dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.3.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation files('libs/classes.jar')
}


task deleteOldJar(type: Delete) {
delete 'release/AndroidPlugin.jar'
}

//task to export contents as jar
task exportJar(type: Copy) {
from('build/intermediates/aar_main_jar/release/')
into('release/')
include('classes.jar')
///Rename the jar
rename('classes.jar', 'AndroidPlugin.jar')
}

exportJar.dependsOn(deleteOldJar, build)

Android Studio中执行Sync Project with Gradle Files,然后在右上角Gradle中Module name/Task/other/下执行exportJar:

android_unity_root7

Project栏目下Module name/release中放有build生成的AndroidPlugin.jar。将AndroidPlugin.jar和AndroidManifest.xml复制到Unity项目的Assets/Plugins/Android/目录下。使用解压缩软件打开AndroidPlugin.jar,并且删除BuildConfig.class:

android_unity_root8

Unity中编写测试脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class test : MonoBehaviour
{
// Start is called before the first frame update
void Awake()
{

Debug.Log("==================");
AndroidJavaObject activity = new AndroidJavaObject ("com.cvte.imagetracker.MainActivity");
Debug.Log("GetRoot");
activity.Call("GetRoot");
Debug.Log("==================");
}

// Update is called once per frame
void Update()
{


}

}

Scripting Backend使用IL2CPP,并且注意Package Name和API Level与Java项目中一致。

android_unity_root2

打包,放到装有Magisk的手机上执行,启动的时候就会提示APP授予超级用户权限。

android_unity_root9


  1. https://blog.csdn.net/weixin_43271060/article/details/109512768 ↩ ↩

  2. https://blog.csdn.net/mChenys/article/details/86701272 ↩

Building libuvc on Ubuntu

Posted on 2021-08-17   |   In Tech , Linux   |  
git clone https://github.com/saki4510t/UVCCamera.git

打开Android Studio,File->Open打开UVCCamera文件夹。

修改Project/build.gradle文件,修改以下部分:

ext {
supportLibVersion = '27.1.1' // variable that can be referenced to keep support libs consistent
commonLibVersion= '2.12.4'
versionBuildTool = '27.0.3'
versionCompiler = 27
versionTarget = 27
versionNameString = '1.0.0'
javaSourceCompatibility = JavaVersion.VERSION_1_8
javaTargetCompatibility = JavaVersion.VERSION_1_8
}

File->Project Structure,修改Android SDK location和Android NDK location,例如Android SDK location: /home/luohanjie/Android/Sdk,Android NDK location: /home/luohanjie/Android/Sdk/ndk/android-ndk-r21。

修改Project/libuvccamera/src/main/jni/Application.mk,

APP_PLATFORM := android-21
APP_ABI := armeabi-v7a arm64-v8a x86_64
#APP_OPTIM := debug
APP_OPTIM := release

然后Build->Make Project。

Unity Physical Camera如何使用真实摄像头内参

Posted on 2021-04-16   |   In Tech , AR   |  

通过OpneCV等工具提供的标定方法[1],获得真实摄像头的针孔模型内参矩阵$K$:

$$K= {\begin{bmatrix} {f_x}&0&{c_x} \newline 0&{f_y}&{c_y} \newline 0&0&1 \end{bmatrix}}$$

Unity的Physcial Camera[2]仿真了真实世界的摄像头,可以将标定后的内参矩阵信息输入到Unity的Physcial Camera中,方便两者配合使用。

Unity中的转换方法:

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.UI;

public class MyCamera : MonoBehaviour
{
public string camera_name = "Integrated Camera"; // USB Video Device //Integrated Camera //Virtual Camera
public int width = 1280;
public int height = 720;
public int fps = 120;
public float focal = 28F;
public float fx = 1087.4199F;
public float fy = 1087.4199F;
public float cx = 640F;
public float cy = 360F;
public float skew = 0F;
public AspectRatioFitter fit;
private RawImage cambackground = null;
private Camera cam_obj = null;
private WebCamTexture cam = null;
private volatile Color32[] cam_data = null;
private Texture2D tex = null;

IEnumerator Start()
{
cambackground = GameObject.FindWithTag("CamBackground").GetComponent<RawImage>();
cam_obj = GameObject.FindWithTag("MainCamera").GetComponent<Camera>();

yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);

if (Application.HasUserAuthorization(UserAuthorization.WebCam))
{
WebCamDevice[] devices = WebCamTexture.devices;

if (devices.Length == 0)
{
Debug.Log("No camera detected!");
yield break;
}

bool find_camera = false;

for (int i = 0; i < devices.Length; i++)
{
Debug.Log("Found camera:" + devices[i].name);
if (camera_name.Equals(devices[i].name)) {
find_camera = true;
}
}

if (!find_camera)
{
Debug.Log("Unable to find camera: " + camera_name + "\n");
Debug.Log("Open the first camera" + devices[0].name + "\n");
camera_name = devices[0].name;
}

cam = new WebCamTexture(camera_name, width, height, fps);

WebCamTexture.allowThreadedTextureCreation = true;
WebCamTexture.streamingTextureDiscardUnusedMips = true;

cam.Play();

width = cam.width;
height = cam.height;

// ******************************************************
// Transfer Real Camera Inrinsic Parameters to Unity Physical Camera Parameters
cam_obj.usePhysicalProperties = true;
cam_obj.focalLength = focal;
cam_obj.sensorSize = new Vector2(focal * width / fx,
focal * height / fy);
cam_obj.lensShift = new Vector2(-(cx - width * 0.5f) / width,
(cy - height * 0.5f) / height);
// ******************************************************

Debug.Log(camera_name +" Running...\n");
}
}

void Update()
{
if (cam == null || !cam.isPlaying) return;

if (cam_data == null)
{
cam_data = new Color32[width * height];
tex = new Texture2D(width, height);
}

cam_data = cam.GetPixels32();
tex.SetPixels32(cam_data);
tex.Apply();
cambackground.texture = tex;

fit.aspectRatio = (float)cam.width / (float)cam.height;

}
}

其中float focal为任意设定的参数(因为无法通过标定获得),一般选择一个靠近真实值的值。


  1. https://docs.opencv.org/master/dc/dbb/tutorial_py_calibration.html ↩

  2. https://docs.unity3d.com/Manual/PhysicalCameras.html ↩

通过串口实现SystemView分析FreeRTOS v10.3.1

Posted on 2021-03-22   |   In Tech , Hardware   |  

准备文件

我的STM32项目是经由STM32CubeMX v6.2.0生成的Makefile项目;使用VS-Code-STM32-IDE来生成VS Code项目;使用v10.3.1的FreeRTOS系统;芯片为STM32F407VE;使用USART1作为输出端口,开启DMA传输。

下载SystemView v3.30版本。在安装目录内的SystemView_V330\Src文件夹中,将SEGGER和Sample内的相关文件复制到STM32项目的文件夹STM32_Project\Middlewares\Third_Party\SystemView中[1][2]。注意根据项目的需求,选择复制Sample中对应的系统和SEGGER\Syscalls中对应的编译器:

SystemView
├── Config
│ ├── Global.h
│ ├── SEGGER_RTT_Conf.h
│ ├── SEGGER_SYSVIEW_Conf.h
│ └── SEGGER_SYSVIEW_Config_FreeRTOS.c
└── SEGGER
├── SEGGER.h
├── SEGGER_RTT.c
├── SEGGER_RTT.h
├── SEGGER_RTT_ASM_ARMv7M.s
├── SEGGER_RTT_printf.c
├── SEGGER_SYSVIEW.c
├── SEGGER_SYSVIEW.h
├── SEGGER_SYSVIEW_ConfDefaults.h
├── SEGGER_SYSVIEW_FreeRTOS.c
├── SEGGER_SYSVIEW_FreeRTOS.h
├── SEGGER_SYSVIEW_Int.h
└── Syscalls
└── SEGGER_RTT_Syscalls_GCC.c

注意:SEGGER_RTT_ASM_ARMv7M.S需要改名为SEGGER_RTT_ASM_ARMv7M.s,不然后面编译时会出现No rule to make target错误。

FreeRTOS补丁

SystemView提供了针对FreeRTOS v10.0.0版本的补丁FreeRTOSV10_Core.patch,但不适合新的版本。这里我们提供了针对FreeRTOS v10.3.1版本的补丁。复制下面内容,并且保存名为patch的文件,并且放到STM32_Project\Middlewares\Third_Party,内含FreeRTOS的文件夹下:

diff -rupwN FreeRTOS/Source/include/FreeRTOS.h FreeRTOS_systemview/Source/include/FreeRTOS.h
--- FreeRTOS/Source/include/FreeRTOS.h 2021-03-22 00:24:29.699956400 +0800
+++ FreeRTOS_systemview/Source/include/FreeRTOS.h 2021-03-14 03:13:48.049285300 +0800
@@ -160,10 +160,6 @@ extern "C" {
#define INCLUDE_uxTaskGetStackHighWaterMark2 0
#endif

-#ifndef INCLUDE_pxTaskGetStackStart
- #define INCLUDE_pxTaskGetStackStart 0
-#endif
-
#ifndef INCLUDE_eTaskGetState
#define INCLUDE_eTaskGetState 0
#endif
@@ -420,22 +416,6 @@ hold explicit before calling the code. *
#define tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )
#endif

-#ifndef traceREADDED_TASK_TO_READY_STATE
- #define traceREADDED_TASK_TO_READY_STATE( pxTCB ) traceMOVED_TASK_TO_READY_STATE( pxTCB )
-#endif
-
-#ifndef traceMOVED_TASK_TO_DELAYED_LIST
- #define traceMOVED_TASK_TO_DELAYED_LIST()
-#endif
-
-#ifndef traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST
- #define traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST()
-#endif
-
-#ifndef traceMOVED_TASK_TO_SUSPENDED_LIST
- #define traceMOVED_TASK_TO_SUSPENDED_LIST( pxTCB )
-#endif
-
#ifndef traceQUEUE_CREATE
#define traceQUEUE_CREATE( pxNewQueue )
#endif
@@ -680,18 +660,6 @@ hold explicit before calling the code. *
#define traceTASK_NOTIFY_GIVE_FROM_ISR()
#endif

-#ifndef traceISR_EXIT_TO_SCHEDULER
- #define traceISR_EXIT_TO_SCHEDULER()
-#endif
-
-#ifndef traceISR_EXIT
- #define traceISR_EXIT()
-#endif
-
-#ifndef traceISR_ENTER
- #define traceISR_ENTER()
-#endif
-
#ifndef traceSTREAM_BUFFER_CREATE_FAILED
#define traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer )
#endif
diff -rupwN FreeRTOS/Source/include/task.h FreeRTOS_systemview/Source/include/task.h
--- FreeRTOS/Source/include/task.h 2021-03-22 00:27:05.253377700 +0800
+++ FreeRTOS_systemview/Source/include/task.h 2021-03-14 03:13:48.062250900 +0800
@@ -1468,25 +1468,6 @@ UBaseType_t uxTaskGetStackHighWaterMark(
*/
configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;

-/**
- * task.h
- * <PRE>uint8_t* pxTaskGetStackStart( TaskHandle_t xTask);</PRE>
- *
- * INCLUDE_pxTaskGetStackStart must be set to 1 in FreeRTOSConfig.h for
- * this function to be available.
- *
- * Returns the start of the stack associated with xTask. That is,
- * the highest stack memory address on architectures where the stack grows down
- * from high memory, and the lowest memory address on architectures where the
- * stack grows up from low memory.
- *
- * @param xTask Handle of the task associated with the stack returned.
- * Set xTask to NULL to return the stack of the calling task.
- *
- * @return A pointer to the start of the stack.
- */

-uint8_t* pxTaskGetStackStart( TaskHandle_t xTask) PRIVILEGED_FUNCTION;
-
/* When using trace macros it is sometimes necessary to include task.h before
FreeRTOS.h. When this is done TaskHookFunction_t will not yet have been defined,
so the following two prototypes will cause a compilation error. This can be
diff -rupwN FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c FreeRTOS_systemview/Source/portable/GCC/ARM_CM4F/port.c
--- FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c 2021-03-22 00:29:26.581083000 +0800
+++ FreeRTOS_systemview/Source/portable/GCC/ARM_CM4F/port.c 2021-03-14 03:13:48.114111800 +0800
@@ -492,20 +492,14 @@ void xPortSysTickHandler( void )
save and then restore the interrupt mask value as its value is already
known. */

portDISABLE_INTERRUPTS();
- traceISR_ENTER();
{
/* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE )
{
- traceISR_EXIT_TO_SCHEDULER();
/* A context switch is required. Context switching is performed in
the PendSV interrupt. Pend the PendSV interrupt. */

portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
- else
- {
- traceISR_EXIT();
- }
}
portENABLE_INTERRUPTS();
}
diff -rupwN FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h FreeRTOS_systemview/Source/portable/GCC/ARM_CM4F/portmacro.h
--- FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h 2021-03-22 00:30:13.377937500 +0800
+++ FreeRTOS_systemview/Source/portable/GCC/ARM_CM4F/portmacro.h 2021-03-14 03:13:48.115109400 +0800
@@ -89,7 +89,7 @@ typedef unsigned long UBaseType_t;

#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
-#define portEND_SWITCHING_ISR( xSwitchRequired ) { if( xSwitchRequired != pdFALSE ) { traceISR_EXIT_TO_SCHEDULER(); portYIELD(); } else { traceISR_EXIT(); } }
+#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/

diff -rupwN FreeRTOS/Source/tasks.c FreeRTOS_systemview/Source/tasks.c
--- FreeRTOS/Source/tasks.c 2021-03-22 00:48:55.028709000 +0800
+++ FreeRTOS_systemview/Source/tasks.c 2021-03-14 03:13:48.213845800 +0800
@@ -220,16 +220,6 @@ count overflows. */
taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \
tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )
-/*
- * Place the task represented by pxTCB which has been in a ready list before
- * into the appropriate ready list for the task.
- * It is inserted at the end of the list.
- */
-#define prvReaddTaskToReadyList( pxTCB ) \
- traceREADDED_TASK_TO_READY_STATE( pxTCB ); \
- taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
- vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \
- tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )
/*-----------------------------------------------------------*/

/*
@@ -1682,7 +1672,7 @@ static void prvAddNewTaskToReadyList( TC
{
mtCOVERAGE_TEST_MARKER();
}
- prvReaddTaskToReadyList( pxTCB );
+ prvAddTaskToReadyList( pxTCB );
}
else
{
@@ -1744,7 +1734,6 @@ static void prvAddNewTaskToReadyList( TC
mtCOVERAGE_TEST_MARKER();
}

- traceMOVED_TASK_TO_SUSPENDED_LIST(pxTCB);
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );

#if( configUSE_TASK_NOTIFICATIONS == 1 )
@@ -3893,20 +3882,6 @@ static void prvCheckTasksWaitingTerminat
#endif /* INCLUDE_uxTaskGetStackHighWaterMark */
/*-----------------------------------------------------------*/

-#if (INCLUDE_pxTaskGetStackStart == 1)
- uint8_t* pxTaskGetStackStart( TaskHandle_t xTask)
- {
- TCB_t *pxTCB;
- UBaseType_t uxReturn;
- (void)uxReturn;
-
- pxTCB = prvGetTCBFromHandle( xTask );
- return ( uint8_t * ) pxTCB->pxStack;
- }
-
-#endif /* INCLUDE_pxTaskGetStackStart */
-/*-----------------------------------------------------------*/
-
#if ( INCLUDE_vTaskDelete == 1 )

static void prvDeleteTCB( TCB_t *pxTCB )
@@ -4081,7 +4056,7 @@ TCB_t *pxTCB;

/* Inherit the priority before being moved into the new list. */
pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
- prvReaddTaskToReadyList( pxMutexHolderTCB );
+ prvAddTaskToReadyList( pxMutexHolderTCB );
}
else
{
@@ -4171,7 +4146,7 @@ TCB_t *pxTCB;
any other purpose if this task is running, and it must be
running to give back the mutex. */
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
- prvReaddTaskToReadyList( pxTCB );
+ prvAddTaskToReadyList( pxTCB );

/* Return true to indicate that a context switch is required.
This is only actually required in the corner case whereby
@@ -5233,7 +5208,6 @@ const TickType_t xConstTickCount = xTick
/* Add the task to the suspended task list instead of a delayed task
list to ensure it is not woken by a timing event. It will block
indefinitely. */
- traceMOVED_TASK_TO_SUSPENDED_LIST(pxCurrentTCB);
vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else
@@ -5250,14 +5224,12 @@ const TickType_t xConstTickCount = xTick
{
/* Wake time has overflowed. Place this item in the overflow
list. */
- traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST();
vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else
{
/* The wake time has not overflowed, so the current block list
is used. */
- traceMOVED_TASK_TO_DELAYED_LIST();
vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );

/* If the task entering the blocked state was placed at the
@@ -5287,13 +5259,11 @@ const TickType_t xConstTickCount = xTick
if( xTimeToWake < xConstTickCount )
{
/* Wake time has overflowed. Place this item in the overflow list. */
- traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST();
vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else
{
/* The wake time has not overflowed, so the current block list is used. */
- traceMOVED_TASK_TO_DELAYED_LIST();
vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );

/* If the task entering the blocked state was placed at the head of the

在命令行窗口中输入打补丁指令:

patch -p0 < patch

监听程序

在STM32_Project\Inc\FreeRTOSConfig.h下添加以下语句:

/* USER CODE BEGIN Defines */
/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */

#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_pxTaskGetStackStart 1

#include "SEGGER_SYSVIEW_FreeRTOS.h"
/* USER CODE END Defines */

新建文件STM32_Project\Modules\include\systemview_task.h和STM32_Project\Modules\src\systemview_task.c[3]:

#ifndef __SYSTEMVIEW_TASK_H
#define __SYSTEMVIEW_TASK_H

#include "FreeRTOS.h"

#include "config.h"
#include "utils.h"
#include "usart_com.h"

void SystemViewLaunch(void);

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);

#endif /* __SYSTEMVIEW_TASK_H */
#include "systemview_task.h"

#define SYSVIEW_SINGLE_TX 256

TaskHandle_t system_view_notify;

STATIC_MEM_TASK_ALLOC(systemview_task, SYSTEMVIEW_TASK_STACKSIZE);
static void SystemViewTask(void *param);

uint8_t hello_message[32] = {
'S', 'E', 'G', 'G', 'E', 'R', ' ',
'S', 'y', 's', 't', 'e', 'm', 'V', 'i', 'e', 'w',
' ', 'V', '0' + SEGGER_SYSVIEW_MAJOR,
'.', '0' + (SEGGER_SYSVIEW_MINOR / 10),
'0' + (SEGGER_SYSVIEW_MINOR % 10),
'.', '0' + (SEGGER_SYSVIEW_REV / 10),
'0' + (SEGGER_SYSVIEW_REV % 10),
'\0', 0, 0, 0, 0, 0};

void SystemViewLaunch(void) {

CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;

SEGGER_SYSVIEW_Conf();

STATIC_MEM_TASK_CREATE(systemview_task, SystemViewTask, "SystemViewTask", NULL, SYSTEMVIEW_TASK_PRI);
}

void SystemViewTask(void *param) {
system_view_notify = xTaskGetCurrentTaskHandle();

// 获取Channel ID
int channel_id = SEGGER_SYSVIEW_GetChannelID();

//发送HELLO包
HAL_UART_Transmit_DMA(&huart1, hello_message, 32);

uint8_t rx_buf;
uint8_t tx_buf[SYSVIEW_SINGLE_TX];
uint32_t notify_flag;
bool dma_in_progress = true;
TickType_t prev_send;

//启动记录
SEGGER_SYSVIEW_Start();

while (1) {
if (xTaskNotifyWait(0x00, 0x03, &notify_flag, pdMS_TO_TICKS(400)) == pdTRUE) {
if (notify_flag & 0x01) {
SEGGER_RTT_WriteDownBufferNoLock(channel_id, &rx_buf, 0x01);
HAL_UART_Receive_IT(&huart1, &rx_buf, 0x01);
} else if (notify_flag & 0x02) {
if (dma_in_progress) {
dma_in_progress = false;
prev_send = xTaskGetTickCount();
}
}
}

if (dma_in_progress == false && xTaskGetTickCount() - prev_send >= pdMS_TO_TICKS(400)) {
unsigned int tx_length = SEGGER_RTT_GetBytesInBuffer(channel_id);
if (tx_length >= SYSVIEW_SINGLE_TX) {
uint32_t num = SEGGER_RTT_ReadUpBufferNoLock(channel_id, tx_buf, SYSVIEW_SINGLE_TX);
HAL_UART_Transmit_DMA(&huart1, tx_buf, num);
} else if (tx_length != 0) {
uint32_t num = SEGGER_RTT_ReadUpBufferNoLock(channel_id, tx_buf, tx_length);
HAL_UART_Transmit_DMA(&huart1, tx_buf, num);
}
dma_in_progress = true;
}

}
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
BaseType_t higher_woken = pdFALSE;
xTaskNotifyFromISR(system_view_notify, 0x01, eSetBits, &higher_woken);
portYIELD_FROM_ISR(higher_woken);
}
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
BaseType_t higher_woken = pdFALSE;
xTaskNotifyFromISR(system_view_notify, 0x02, eSetBits, &higher_woken);
portYIELD_FROM_ISR(higher_woken);
}
}

修改STM32_Project\Src\main.c函数:

...
#include "systemview_task.h"
...

...
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_TIM4_Init();
MX_USART2_UART_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */

SystemViewLaunch();

/* USER CODE END 2 */

/* Call init function for freertos objects (in freertos.c) */
MX_FREERTOS_Init();
/* Start scheduler */
osKernelStart();
...

修改STM32_Project\.vscode\c_cpp_properties.json,添加:

...
"____________________USER_FIELDS_CAN_BE_MODIFIED____________________": "",
"user_cSources": [
"Modules/src/usart_com.c",
"Modules/src/motor.c",
"Modules/src/mavlink_task.c",
"Modules/src/utils.c",
"Modules/src/mpu6050.c",
"Modules/src/ms5611.c",
"Modules/src/hmc5883l.c",
"Modules/src/sensors.c",
"Modules/src/i2c1.c",
"Modules/src/dmp.c",
"Modules/src/system_task.c",
"Modules/src/systemview_task.c",
"Middlewares/Third_Party/SystemView/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c",
"Middlewares/Third_Party/SystemView/SEGGER/SEGGER_RTT_printf.c",
"Middlewares/Third_Party/SystemView/SEGGER/SEGGER_RTT.c",
"Middlewares/Third_Party/SystemView/SEGGER/SEGGER_SYSVIEW_FreeRTOS.c",
"Middlewares/Third_Party/SystemView/SEGGER/SEGGER_SYSVIEW.c",
"Middlewares/Third_Party/SystemView/SEGGER/Syscalls/SEGGER_RTT_Syscalls_GCC.c"
],
"user_asmSources": [
"Middlewares/Third_Party/SystemView/SEGGER/SEGGER_RTT_ASM_ARMv7M.s"
],
"user_ldSources": [],
"user_cIncludes": [
"Modules/include",
"Middlewares/Third_Party/SystemView/Config",
"Middlewares/Third_Party/SystemView/SEGGER"
],
"user_asmIncludes": [],
"user_ldIncludes": [],
"user_cDefines": [],
"user_asmDefines": [],
"user_cFlags": [],
"user_asmFlags": [],
"user_ldFlags": [
"-u _printf_float"
],
...

编译并且烧录到单片机中。

SystemView

打开SystemView软件,打开Target->Recorder Configuration,选择UART并且填好相应的串口和波特率。

点击Start Recording,重启单片机,成功监控FreeRTOS:

system_vie

Github: https://github.com/HanjieLuo/drone


  1. https://github.com/nghiaphamsg/STM32F4_FreeRTOS/blob/master/002_SEGGER_Tools/README.md ↩

  2. https://www.segger.com/downloads/systemview/UM08027 ↩

  3. https://blog.imi.moe/systemview-freertos/ ↩

12…23
Hanjie Luo

Hanjie Luo

113 posts
17 categories
110 tags
github
© 2016 - 2021 Hanjie Luo
Powered by Hexo
Theme - NexT.Pisces