在Xilinx ZCU102上移植ThreadX SMP

  • Post author:
  • Post category:其他




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 assorted
       create 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即可。



版权声明:本文为weixin_43739110原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。