在Xilinx ZCU102上移植ThreadX SMP

在Xilinx ZCU102上移植ThreadX SMP

  • ZCU102移植ThreadX SMP
    • 准备工作
      • 获取例程
      • 安装Xilinx SDK 2018.03
    • 移植
      • 导入例程
      • FSBL引导
      • 编译
      • 运行
    • 验证SMP
    • 如何在tx工程中使用xil_printf辅助调试
      • 方法如下:

ZCU102移植ThreadX SMP

准备工作

获取例程

ThreadX官方没有直接提供Xilinx ZCU102的移植例程,但是可以发邮件给azure-rtos-support@microsoft.com或者sclarson@microsoft.com,说明你想要移植的板子,就会发给你。

我收到了两个例程:

  • zcu102_cortex-a53_smp_full_source.zip
  • zcu102_cortex-r5_full_source.zip

百度盘链接

提取码:am85

前者cortex-a53例程支持SMP,cortex-r5例程不支持。

我只运行了cortex-a53例程,若cortex-r5例程有所不同则仅供参考。

安装Xilinx SDK 2018.03

cortex-a53例程是用Xilinx SDK 2018.02完成的,但是当我安装完2018.02版本,导入并编译成功后,运行时没有任何反应。

查到是因为我使用的ZCU102套件(Kit label大于0432055-05)是新版的,不能在2018.02版本使用。参考

我也试过Vitis 2020.02,可能版本差太多,导入失败。

SDK 2019.01可以编译,不过后续没有尝试。

移植

导入例程

1.创建一个存放工程的文件夹。

2.打开SDK 2018.03,选择工程文件夹的路径,点击OK

在这里插入图片描述
3.左上角菜单栏选择 File->Import ,弹出如下窗口,选择General->Existing Projects into Workspcae,点击Next

在这里插入图片描述
4.点击Select root directory右边的Browse…,选择cortex-a53例程,点击确定。

在这里插入图片描述
5.如果不需要网络,那么只需要勾选:

  • demo_threadx
  • tx
  • libmetal
  • zcu102_apu_bsp(这个版本有点低,后面没有用到)
  • ZCU102_hw_platform

点击Finish

在这里插入图片描述

FSBL引导

导入工程后,还不能直接编译运行,还要创建一个FSBL应用程序作为引导,因为原来的psu_init已经不适用了。参考

1.File->New->Application Project,输入工程名,其他都一样的选择,Next

在这里插入图片描述
2.选择Zynq MP FSBL模版,再点Finish

在这里插入图片描述

编译

1.依次右键编译 Build Project

  • tx
  • libmetal
  • fsbl

2.右键demo_threadx,Properties->Project References,去掉zcu102_apu_bsp的勾选,再勾选fsbl_bsp

3.再点C/C++ General->Paths and Symbols,在右侧Includes标签栏中,Edit原来zcu102_apu_bsp的头文件路径,改为fsbl_bsp的头文件。

4.在右侧Library Paths标签栏中,Edit原来zcu102_apu_bsp的库路径,改为fsbl_bsp的库,点OK保存。

5.右键编译demo_threadx。

运行

1.右键 fsbl 工程,Run as->Run Configurations…

2.双击Xilinx C/C++ application(System Debugger)

3.在右侧Target Setup标签栏,去掉Run psu_init的勾选。

在这里插入图片描述

4.开启ZCU102,点击Run,串口输出:

在这里插入图片描述
5.对demo_threadx工程重复前四个步骤,弹出是否终止已经运行的工程选择是。

在这里插入图片描述

验证SMP

tx_thread_smp_core_get() 函数可以返回该线程被哪个核执行,利用它改写demo_threadx.c文件。

大概过程就是:有4个线程不停将运行自身的核心编号存储在一个数组中,还有一个线程则不停打印数组和自身的核心编号。

因为cortex-a53有4个核心,所以设置了5个线程。

修改后的demo_threadx.c:

#include   "tx_api.h"/* XXX prevent xil_types.h from redefining LONG and ULONG types */
#define LONG LONG
#define ULONG ULONG#include   "xil_printf.h"#define     DEMO_STACK_SIZE         1024
#define     DEMO_BYTE_POOL_SIZE     9120
#define     DEMO_BLOCK_POOL_SIZE    100
#define     DEMO_QUEUE_SIZE         100/* Define the ThreadX object control blocks...  */
TX_THREAD               thread_0;
TX_THREAD               thread_1;
TX_THREAD               thread_2;
TX_THREAD               thread_3;
TX_THREAD               thread_4;
TX_QUEUE                queue_0;
TX_SEMAPHORE            semaphore_0;
TX_MUTEX                mutex_0;
TX_EVENT_FLAGS_GROUP    event_flags_0;
TX_BYTE_POOL            byte_pool_0;
TX_BLOCK_POOL           block_pool_0;/* Define the counters used in the demo application...  */
ULONG           thread_0_counter;
ULONG           thread_1_counter;
ULONG           thread_1_messages_sent;
ULONG           thread_2_counter;
ULONG           thread_2_messages_received;
ULONG           thread_3_counter;
ULONG           thread_4_counter;UCHAR           memory_pool[DEMO_BYTE_POOL_SIZE];/* Define thread prototypes.  */
void    thread_0_entry(ULONG thread_input);
void    thread_1_entry(ULONG thread_input);
void    thread_2_entry(ULONG thread_input);
void    thread_3_entry(ULONG thread_input);
void    thread_4_entry(ULONG thread_input);int core_num[4];//暂存核心编号/* Define main entry point.  */
int main()
{/* Enter the ThreadX kernel.  */tx_kernel_enter();
}/* Define what the initial system looks like.  */void    tx_application_define(void *first_unused_memory)
{CHAR    *pointer;/* Create a byte memory pool from which to allocate the thread stacks.  */tx_byte_pool_create(&byte_pool_0, "byte pool 0", memory_pool, DEMO_BYTE_POOL_SIZE);/* Put system definition stuff in here, e.g. thread creates and other assortedcreate information.  *//* Allocate the stack for thread 0.  */tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);/* Create the main thread.  */tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,  pointer, DEMO_STACK_SIZE, 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);/* Allocate the stack for thread 1.  */tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,  pointer, DEMO_STACK_SIZE, 16, 16, 4, TX_AUTO_START);/* Allocate the stack for thread 2.  */tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2,  pointer, DEMO_STACK_SIZE, 16, 16, 4, TX_AUTO_START);/* Allocate the stack for thread 3.  */tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);tx_thread_create(&thread_3, "thread 3", thread_3_entry, 3,pointer, DEMO_STACK_SIZE,4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);/* Allocate the stack for thread 4.  */tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);tx_thread_create(&thread_4, "thread 4", thread_4_entry, 4,pointer, DEMO_STACK_SIZE,4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
}/* Define the test threads.  */
void    thread_0_entry(ULONG thread_input)
{while(1){core_num[0] = tx_thread_smp_core_get();tx_thread_sleep(100);}
}void    thread_1_entry(ULONG thread_input)
{while(1){core_num[1] = tx_thread_smp_core_get();tx_thread_sleep(200);}
}void    thread_2_entry(ULONG thread_input)
{while(1){core_num[2] = tx_thread_smp_core_get();tx_thread_sleep(150);}
}void    thread_3_entry(ULONG thread_input)
{while(1){xil_printf("thread_0 : core %lu\r\n",core_num[0]);xil_printf("thread_1 : core %lu\r\n",core_num[1]);xil_printf("thread_2 : core %lu\r\n",core_num[2]);xil_printf("thread_3 : core %lu\r\n",_tx_thread_smp_core_get());xil_printf("thread_4 : core %lu\r\n",core_num[3]);tx_thread_sleep(100);}
}void    thread_4_entry(ULONG thread_input)
{while(1){core_num[3] = tx_thread_smp_core_get();tx_thread_sleep(200);}
}

结果:

在这里插入图片描述
原来一开始是每个线程各打各的信息,结果出来一堆乱序的结果,才改成这样。

现在想来,这其实也是一个多核运行的证据,如果是单核那么即使多线程也不会乱序。

core 0只有一开始引导用到,(猜测)可能是因为core 0需要运行一些隐藏线程,比如定时器线程之类,所以根据平衡分配线程的算法就没有给core 0再分配其他线程。

如何在tx工程中使用xil_printf辅助调试

例程中,是先编译tx工程生成一个libtx.a库文件,然后让demo_threadx工程包含这个库文件。所以tx工程中一开始不能使用xil_printf。

但如果想要探究ThreadX内部的机制,一般来说串口打印信息是必不可少的。

方法如下:

1.右键tx工程,Properties->Project References,勾选fsbl_bsp

2.再点C/C++ General->Paths and Symbols,在右侧Includes标签栏中,Add头文件fsbl_bsp的路径/fsbl_bsp/psu_cortexa53_0/include

3.再点C/C++ Build->Settings,在右侧Tool Settings标签栏中,点击ARM v8 gcc compiler->Inferred Options->Software Platform,在Software Platform Inferred Flags中填写-lxil

4.打开tx/src/tx_port.h文件,在171行左右插入以下代码:

/* XXX prevent xil_types.h from redefining LONG and ULONG types */
#define LONG LONG
#define ULONG ULONG
#include   "xil_printf.h"

这是避免ThreadX和Xilinx SDK之间关于LONG 和ULONG 的重复定义。

再重新编译tx即可。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部