Xilinx软件开发:FreeRTOS快速入门

article/2025/11/10 19:55:27

目录    
第一章. 测试环境和软件版本    
第二章. 创建hello world    
第三章. 创建FreeRTOS2    
第四章. 增加两个任务    
1. 增加任务    
2. 增加计数    
第五章. 发送增加延时    
第六章. 接收增加消息判断    
第七章. 创建两个生产者    
第八章. 注意事项    
1. 分析xQueueReceive源码    
2. 实际验证xQueueSend传递的数据是否线程安全    
3. 增加打印地址    
第九章. 其他问题    
1. 如何设置Producer 任务以1hz的频率执行?    
2. 如何展开队列以容纳20条消息?    
3. 如何为以下消息类型创建一个长度为5的队列?    
4. 如何修改Consumer代码以仅在队列满时读取消息?    
5. 能否从队列读取所有消息而不是一条消息?    
第十章. 优先级说明    
 


 
第一章.测试环境和软件版本

Win10 
Vivado/Vitis 2020.1

第二章.创建hello world


F:\debug\leo_training\201\FreeRTOS1
 


 

Platform命名为
FreeRTOS_Basic_sys

 

 

 

app命名为
FreeRTOS_Basic_app


注意cpu要选r5_0

 

 

 

 

 


 

第三章.创建FreeRTOS2

参考创建hello world的流程
创建成功后的界面如图

 

把support目录的以下三个文件复制到F:\debug\leo_training\201\FreeRTOS2\FreeRTOS2\src
freertos_hello_world.c
ProducerConsumer.h
ProducerConsumer.c

 

 


然后点debug运行,这时候是个空程序,什么都没做

第四章.增加两个任务


1. 增加任务
打开ProducerConsumer.c
修改setupTasks,创建一个队列和两个任务


void setupTasks() {
  xQueueHandle xQueue = xQueueCreate (10, sizeof (uint32_t));

  xTaskCreate (prvProducer, (const char *) "Prod", configMINIMAL_STACK_SIZE, (void *) xQueue, PRODUCER_PRIORITY, NULL);
  xTaskCreate (prvConsumer, (const char *) "Cons", configMINIMAL_STACK_SIZE, (void *) xQueue, CONSUMER_PRIORITY, NULL);
}

xQueueCreate的定义如下

#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
    #define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) )
#endif


参数1 函数指针
参数2 名字
参数3 堆栈大小
参数4 参数指针
参数5 优先级
参数6 NULL

xTaskCreate的定义如下

#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 200)

    BaseType_t xTaskCreate(    TaskFunction_t pxTaskCode,
                            const char * const pcName,        /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                            const configSTACK_DEPTH_TYPE usStackDepth,
                            void * const pvParameters,
                            UBaseType_t uxPriority,
                            TaskHandle_t * const pxCreatedTask )


2. 增加计数


static void prvProducer(void *pvParameters) {
  BaseType_t counter = 0;

  for (;;) {
   counter++;
   xil_printf("Producer %d\r\n", counter);
  }
}

/*-----------------------------------------------------------*/
static void prvConsumer(void *pvParameters) {
  BaseType_t counter = 0;
  for (;;) {
    counter++;
    xil_printf("Consumer %d\r\n", counter);
 }
}

可以看到此时打印得非常快


第五章.发送增加延时


我们在prvProducer中增加延时

static void prvProducer(void *pvParameters) {
  xQueueHandle xQueue = (xQueueHandle) pvParameters;
  BaseType_t counter = 0;
  TickType_t xLastWakeTime = xTaskGetTickCount ();
  TickType_t xFreq = 500 / portTICK_RATE_MS;

  for (;;) {
      vTaskDelayUntil (&xLastWakeTime, xFreq);
      counter++;
      if (uxQueueSpacesAvailable(xQueue) != 0) {
         if (xQueueSendToBack(xQueue, &counter, 0) != pdPASS) {
            xil_printf ("Producer: Error inserting into queue\r\n");
         }
         else
            xil_printf ("Producer Send counter=%d\r\n", counter);
      }
   }
}

vTaskDelayUntil  绝对延时 参数2是频率    

#define portTICK_RATE_MS portTICK_PERIOD_MS
#define portTICK_PERIOD_MS     ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define configTICK_RATE_HZ (100)

uxQueueSpacesAvailable用于查询队列中可用的空闲空间数量,不为0,队列有效
xQueueSendToBack  将数据发送至队尾,返回pdPASS,发送成功

#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )

第六章.接收增加消息判断

static void prvConsumer(void *pvParameters) {
  xQueueHandle xQueue = (xQueueHandle) pvParameters;
  BaseType_t counter = 0;

  for (;;) {
      BaseType_t message;
       counter++;
      if (xQueueReceive (xQueue, &message, portMAX_DELAY) != pdPASS) {
         xil_printf ("Consumer: Error upon reception of message\r\n");
      } else {
         xil_printf ("Consumer: Received %d counter=%d\r\n", message, counter);
      }
  }
}


第七章.创建两个生产者

 

void setupTasks() {
  xQueueHandle xQueue = xQueueCreate (10, sizeof (uint32_t));

  xTaskCreate (prvProducer, (const char *) "Prod", configMINIMAL_STACK_SIZE, (void *) xQueue, PRODUCER_PRIORITY, NULL);
  xTaskCreate (prvProducer2, (const char *) "Prod2", configMINIMAL_STACK_SIZE, (void *) xQueue, PRODUCER_PRIORITY, NULL);

  xTaskCreate (prvConsumer, (const char *) "Cons", configMINIMAL_STACK_SIZE, (void *) xQueue, CONSUMER_PRIORITY, NULL);
}

static void prvProducer2(void *pvParameters) {
  xQueueHandle xQueue = (xQueueHandle) pvParameters;
  BaseType_t counter = 0;
  TickType_t xLastWakeTime = xTaskGetTickCount ();
  TickType_t xFreq = 500 / portTICK_RATE_MS;

  for (;;) {
      vTaskDelayUntil (&xLastWakeTime, xFreq);
      counter++;
      if (uxQueueSpacesAvailable(xQueue) != 0) {
         if (xQueueSendToBack(xQueue, &counter, 0) != pdPASS) {
            xil_printf ("Producer2: Error inserting into queue\r\n");
         }
         else
            xil_printf ("Producer2 Send counter=%d\r\n", counter);
      }
   }
}


从运行结果可以看到,每次两个Producer各发送了一个消息,Consumer接收到两个消息

 


第八章.注意事项


1. 分析xQueueReceive源码


在queue.c中可以看到数据是复制了一份,所以通过queue传递数据是线程安全的
prvCopyDataFromQueue( pxQueue, pvBuffer )

注意这些操作都是由临界区保护起来的
taskENTER_CRITICAL();
taskEXIT_CRITICAL();

2. 实际验证xQueueSend传递的数据是否线程安全

xQueueSend( xQueue,            /* The queue being written to. */
        HWstring, /* The address of the data being sent. */
        0UL );            /* The block time. */

xQueueReceive(xQueue,                /* The queue being read. */
        Recdstring,    /* Data is read into this address. */
        portMAX_DELAY );    /* Wait without a timeout for data. */

是不是只传了指针,指向的是否是同一地址

3. 增加打印地址


static void prvTxTask( void *pvParameters )
{
const TickType_t x1second = pdMS_TO_TICKS( DELAY_1_SECOND );
xil_printf( "HWstring address: 0x%.8X\r\n", (int)&HWstring );
    for( ;; )
    {
        /* Delay for 1 second. */
        vTaskDelay( x1second );

        /* Send the next value on the queue.  The queue should always be
        empty at this point so a block time of 0 is used. */
        xQueueSend( xQueue,            /* The queue being written to. */
                    HWstring, /* The address of the data being sent. */
                    0UL );            /* The block time. */
    }
}

static void prvRxTask( void *pvParameters )
{
char Recdstring[15] = "";

    for( ;; )
    {
        /* Block to wait for data arriving on the queue. */
        xQueueReceive(xQueue,                /* The queue being read. */
                Recdstring,    /* Data is read into this address. */
                portMAX_DELAY );    /* Wait without a timeout for data. */

        /* Print the received data. */
        xil_printf( "Rx task received string from Tx task: %s 0x%.8X\r\n", Recdstring, (int)&Recdstring );
        RxtaskCntr++;
    }
}


第九章.其他问题


1. 如何设置Producer 任务以1hz的频率执行?


TickType_t xFreq = 1000 / portTICK_RATE_MS; 


 
2. 如何创建队列以容纳20条消息?


xQueueHandle = xQueueCreate(20, sizeof(uint32_t));


3. 如何为以下消息类型创建一个长度为5的队列?

 
struct message {
    int value;
    long lValue;
    float fValue;
};
 
xQueueHandle xQueue = xQueueCreate(5, sizeof(struct message));
队列只需要知道消息个数,而不关心数据类型 

4. 如何修改Consumer代码以仅在队列满时读取消息?

if(uxQueueSpaceAvailable(xQueue) == 0){} 

5. 能否从队列读取所有消息而不是一条消息?

是的。使用类似于
while(uxQueueMessagesWaiting(xQueue)){
//todo
}

第十章.优先级说明

freertos、ucosiii允许优先级相同,ucos2不允许任务的优先级相同
FreeRTOS任务优先:优先级数值越小,任务优先级越低。
ucos、linux任务优先: 优先级数值越小,任务优先级越高

FreeRTOS 中任务的最高优先级是通过 FreeRTOSConfig.h 文件中的 configMAX_PRIORITIES 进行配置的,用户实际可以使用的优先级范围是 0 到 configMAX_PRIORITIES – 1。比如我们配置此宏定义为 5,那么用户可以使用的优先级号是 0,1,2,3,4,不包含 5

用户配置任务的优先级数值越小,那么此任务的优先级越低,空闲任务的优先级是 0。

建议用户配置宏定义 configMAX_PRIORITIES 的最大值不要超过 32,即用户任务可以使用的优先级范围是0到31,设置太大在优先级判断的算法中会浪费时钟周期

如果用户在 FreeRTOSConfig.h 文件中配置宏定义 configUSE_TIME_SLICING 为 1,或者没有配置此宏定义,时间片调度都是使能的。 另外,只要芯片资源允许,可以配置任意多个同优先级任务。没有定义 configUSE_TIME_SLICING,也能使用时间片调度是因为此宏定义默认已经在FreeRTOS.h 文件中使能。

最优先的是中断,其次是用户界面的任务优先,比如按键输入、显示刷新
采集数据,根据用户按键,切换不同的显示内容。
这时候按键判断io电平,用sleep延时消抖,再判断,相同,则发送按键按下消息。
显示任务一般有两个逻辑,没有按键的时候轮显,每隔几秒切换一次画面,有按键则进入按键状态

任务永远不应该从初始函数返回。如果要结束一个任务,销毁任务的正确方法是调用vTaskDelete(NULL);
 
 


http://chatgpt.dhexx.cn/article/f0K2cmfO.shtml

相关文章

关于xilinx vitis 中的报错“fatal error: xil_printf.h: No such file or directory helloworld.c“问题解决

问题源:此问题是由于在VIVADO中使用了自动有AXI—IP造成的; 分析:在自定义了AXI-IP之后,会在自定义IP文件夹下生成“makefile”文件,该文件用于在vitis中生成对应文件的,所以需要修改你自定义IP的文件下的…

Vivado2019.1 ZYNQ7020无Uart SDK调试打印调试信息xil_printf

Vivado2019.1 ZYNQ7020无Uart SDK调试打印调试信息xil_printf Vivado2019.1 ZYNQ7020无Uart SDK调试打印调试信息xil_printf 前提条件:步骤: ** Vivado2019.1 ZYNQ7020无Uart SDK调试打印调试信息xil_printf ** 前提条件: Vivado 2019.1已…

ZYNQ开发中SDK输出串口选择以及打印函数print、printf、xil_printf的差别

ZYNQ开发系列——SDK输出串口选择以及打印函数print、printf、xil_printf的差别 前言两个串口到底是谁在打印?print 和 printf 和 xil_printf 前言 在最初的helloworld工程中,我们实现了通过串口每个1秒钟打印一次Hello World。 这里我们就来搞清楚以下…

Xilinx SDK Xil_In 内存对齐

SDK 的"xil_io.h"中提供了对地址的直接读写操作 不过我在实践中发现,对于Xil_In32(),当偏移为1不断读取时,会出现不正确的值。 我当时是在某连续若干地址中写了 0x0000 00ff(假如基址是0xc000 0000吧),但是读取的时候 0xc000 0001 读取的值是 0x0000 00ff; …

对Xil_Out32未定义的引用

第一次在HLS中遇见一个官方库函数未定义问题,这就把解决方法记录下来。 在创建好工程,写完工程代码后,发现报错如下 ./src/led_controller_test_tut_4A.o:在函数‘main’中:/home/greedyhao/Projects/LearningAndWor…

vivado sdk中xil_out函数对指定的BRAM地址写数据为什么会导致程序挂起?

是有关zynq芯片的网口程序调试的,我在例程lwip_echo_server程序中加入了往指定的bram地址写数据的语句,想要实现PS到PL数据的交互,但是程序执行到xil_out这块直接就运行不下去了,也不会打印下面的东西 下面是BRAM地址在SDK中的声明…

vivado 仿真报错:ERROR: [VRFC 10-2987] ‘xxxxx‘ is not compiled in library ‘xil_defaultlib‘

在Design Sources窗口下,选中报错的IP,比如除法器,右键: 选择第一个Autumatic Update and Compile Order即可。

仿真出现[VRFC 10-2263] Analyzing Verilog fileinto library xil_defaultlib

再Vivado导入quartus的.v文件出现如下情况,仿真例化时例化的模块都是问号。 让我们去仿真文件夹看看。 INFO: [VRFC 10-2263] Analyzing Verilog file "E:/FPGA/sdram0/sdram/sdram.srcs/sim_1/imports/tb_sdram_init/tb_sdram_init.v" into library xil…

GF框架+XIL 项目整合

项目unity版本:2020.3.18f1 XIL版本:Commits on Oct 26, 2021 GameFramework版本:Commits on Sep 28, 2021 UnityGameFramework版本:Commits on Oct 28, 2021 StarForce版本:Commits on Aug 9, 2021 HFS版本:2.3 项目克…

有关 MicroBlaze中xil_prinf/pirntf/print的一些问题

三个函数有什么区别 1.依赖的库文件不同 printf使用C标准库头文件stdio.h print/xil_printf使用xilinx定义的头文件xil_printf.h 2.能够输出的格式不同 print只能打印字符串,不可以带参数格式化输出,函数在print.c中定义 xil_printf可以带参量打印,但是不…

只针对个人遇见卡在Xil_DataAbortHandle循环while的解决办法

只针对本人所遇见的情况&#xff1a; 部分代码&#xff1a;unique_ptr<SatNoSnr[]> SatNo_Snr_Read_main(new SatNoSnr[Wrtie_Num]);// SatNo_Snr_Read_mainflash->FlashRead_JuYan(Wrtie_Num); 当SatNoSnr结构体是129字节(sizeof是136字节)时&#xff0c;上面一…

ZYNQ开发系列——SDK输出串口选择以及打印函数print、printf、xil_printf的差别

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 ZYNQ开发系列——SDK输出串口选择以及打印函数print、printf、xil_printf的差别 前言两个串口到底是谁在打印&#xff1f;print 和 printf 和 xil_printf 前言 在最初的hell…

MBD开发模式下的XIL仿真测试

MBD开发模式下的XIL仿真测试 “想了解MBD模式下的MIL、SIL、PIL、HIL吗&#xff1f;”——虹科 汽车从一个发动机加上几个轮子的简单形态发展到如今机械与电子高度融合的复杂整体&#xff0c;经历了巨变。汽车电子控制单元的数量和复杂度也呈几何级数增加&#xff0c;给软硬件…

SSM 三大框架原理、核心技术,运行流程讲解

作者:arrows 来源:https://www.cnblogs.com/arrows/p/10537733.html 一、Spring部分 1、 Spring的运行流程 第一步&#xff1a;加载配置文件ApplicationContext ac new ClassPathXmlApplicationContext(“beans.xml”); &#xff0c;ApplicationContext接口&#xff0c;它由…

SSM框架介绍以及功能原理

SSM是spingspringMVCmybatis集成的框架。 Spring框架概述 什么是Spring Spring是一个开源框架&#xff0c;Spring是于2003 年兴起的一个轻量级的Java 开发框架&#xff0c;由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来…

ssm框架项目完整流程详解

springMVC项目完整流程详解 1.创建一个maven项目2.修改项目配置&#xff0c;添加tomcat&#xff0c;生成web.xml3.在pom.xml中引入需要用到的包并update project4.在resources下建立如下图所示结构&#xff0c;并创建springmvc-servlet.xml、spring-mybatis.xml、druid.propter…

SSM三大框架工作流程与原理详解

作者&#xff1a;网络笨猪 blog.csdn.net/lyfqyr/article/details/84552278 一、Spring部分 1、Spring的运行流程 第一步&#xff1a;加载配置文件ApplicationContext ac new ClassPathXmlApplicationContext("beans.xml");&#xff0c;ApplicationContext接口&…

SSM框架原理,作用及使用方法,详细解释

1、基本概念 1.1、Spring Spring是一个开源框架&#xff0c;Spring是于2003 年兴起的一个轻量级的Java 开发框架&#xff0c;由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的…

【SSM框架执行流程】

一、单个业务执行流程&#xff1a; 1.tomcat启动: 加载应用的web.xml 2.实例化并初始化Servlet 3.加载spring.xml配置文件创建spring容器&#xff0c;根据配置初始化容器中的对象。 4.浏览器客户端发送请求&#xff0c;例如Hello() 5.请求到达前端控制器&#xff1a;Dispa…

SSM框架原理流程及使用方法

作用&#xff1a; ssm框架是spring MVC &#xff0c;spring和mybatis框架的整合&#xff0c;是标准的MVC模式&#xff0c;将整个系统划分为表现层&#xff0c;controller层&#xff0c;service层&#xff0c;DAO层四层 使用springMVC负责请求的转发和视图管理 spring实现业务…