请选择 进入手机版 | 继续访问电脑版
查看: 2898|回复: 5

【RT1052】+ IMX-RT1052_FreeRTOS学习笔记

[复制链接]

该用户从未签到

16

主题

107

帖子

2

中级会员

Rank: 3Rank: 3

积分
365
最后登录
2022-12-14
发表于 2018-11-10 12:52:19 | 显示全部楼层 |阅读模式
本来好好的Word排版,经过各种复制粘贴,上传、复制粘贴,格式和排版已经惨不忍睹了。请下载pdf查看吧。
NXP的软件部门的人也比较偷懒,这些例程跟我一年前学习LPC54114的例程几乎完全一样。我怀疑所有的NXP的SDK里面的FreeRTOS代码都是这几个例程。
于是我也偷懒一下了。文字基本都跟以前的笔记一样,只有部分代码和所有的图片更新了。
Notes_TOC.png

Notes_TOC1.png Notes_TOC2.png
Notes_Code.png

IMX-RT1052_FreeRTOS学习笔记.pdf (2.1 MB, 下载次数: 89)
回复

使用道具 举报

该用户从未签到

16

主题

107

帖子

2

中级会员

Rank: 3Rank: 3

积分
365
最后登录
2022-12-14
 楼主| 发表于 2018-11-10 12:53:21 | 显示全部楼层
2.5 freertos_sem范例学习
Semaphore信号量消息作为最简单的任务间通讯,通过给任务发送一个信号后,该任务执行该信号量相应的程序。
首先创建一个producer_task任务和三个consumer_task任务,
if (xTaskCreate(producer_task, "PRODUCER_TASK", configMINIMAL_STACK_SIZE + 128, NULL, TASK_PRIO, NULL) != pdPASS)
{
        PRINTF("Task creation failed!.\r\n");
while (1)
;
}
// ......
for (i = 0; i < CONSUMER_LINE_SIZE; i++)
{
if (xTaskCreate(consumer_task, "CONSUMER_TASK", configMINIMAL_STACK_SIZE, (void *)i, TASK_PRIO, NULL) != pdPASS)
{
            PRINTF("Task creation failed!.\r\n");
            vTaskSuspend(NULL);
}
else
{
            PRINTF("Consumer_task %d created.\r\n", i);
}
}
然后创建两个信号量,xSemaphore_producer和xSemaphore_consumer。
xSemaphore_producer = xSemaphoreCreateBinary();
if (xSemaphore_producer == NULL)
{
        PRINTF("xSemaphore_producer creation failed.\r\n");
        vTaskSuspend(NULL);
}
    xSemaphore_consumer = xSemaphoreCreateBinary();
if (xSemaphore_consumer == NULL)
{
        PRINTF("xSemaphore_consumer creation failed.\r\n");
        vTaskSuspend(NULL);
}
在producer_task和consumer_task中,分别对两个信号量进行提供和获取。
/*!
* @brief Task producer_task.
*/
static void producer_task(void *pvParameters)
{
...
while (1)
{
/* Producer is ready to provide item. */
        xSemaphoreGive(xSemaphore_consumer);
/* Producer is waiting when consumer will be ready to accept item. */
if (xSemaphoreTake(xSemaphore_producer, portMAX_DELAY) == pdTRUE)
{
            PRINTF("Producer released item.\r\n");
}
else
{
            PRINTF("Producer is waiting for customer.\r\n");
}
}
}
/*!
* @brief Task consumer_task.
*/
static void consumer_task(void *pvParameters)
{
    PRINTF("Consumer number: %d\r\n", pvParameters);
while (1)
{
/* Consumer is ready to accept. */
        xSemaphoreGive(xSemaphore_producer);
/* Consumer is waiting when producer will be ready to produce item. */
if (xSemaphoreTake(xSemaphore_consumer, portMAX_DELAY) == pdTRUE)
{
            PRINTF("Consumer %d accepted item.\r\n", pvParameters);
}
else
{
            PRINTF("Consumer %d is waiting for producer.\r\n", pvParameters);
}
}
}
完成编译后下载调试,点击运行即可串口输出相关信息。
210  IMX-RT1052_SDK_freertos_sem例程的下载调试图
211  IMX-RT1052_SDK_freertos_sem例程的运行效果图
2.6 freertos_sem_static范例学习
sem_static例程跟sem例程功能完全一致,仅仅是把任务堆栈TaskStack,任务控制块task control block(TCB)、sem结构体的存储位置都静态定义,而sem例程则全部动态分配这些存储。通过diff比较两个工程的FreeRTOSConfig.h文件,可见一斑。
212  sem_staic例程与sem例程的FreeRTOSConfig.h文件对比
Diff对比程序输出,“<”表示第一个文件(sem例程的FreeRTOSConfig.h)的内容,“>”表示第二个文件(sem_static例程的FreeRTOSConfig.h)的内容。
从上图可见,sem例程中,configMINIMAL_STACK_SIZE相对较大有256个StackType_t(uint32_t)大小。而sem_static只有90,因为sem例程通过栈Stack分配semaphore。而sem_static例程则通过静态变量来分配。这从后面的三个宏定义的差异中可以看出。
相应的,调用的创建任务的函数的参数也有不同。
sem例程通过栈Stack动态创建任务:
if (xTaskCreate(producer_task, "PRODUCER_TASK", configMINIMAL_STACK_SIZE + 128, NULL, TASK_PRIO, NULL) != pdPASS)
if (xTaskCreate(consumer_task, "CONSUMER_TASK", configMINIMAL_STACK_SIZE, (void *)i, TASK_PRIO, NULL) != pdPASS)
sem_static例程通过静态声明变量并创建任务:
/* Statically allocated memory for producer_task stack */
static StackType_t ProducerTaskStack[PRODUCER_TASK_STACK_SIZE];
/* Statically allocated memory for producer_task task control block */
static StaticTask_t ProducerTaskTCB;
/* Statically allocated memory for consumer task stacks */
static StackType_t ConsumerTaskStack0[PRODUCER_TASK_STACK_SIZE];
static StackType_t ConsumerTaskStack1[PRODUCER_TASK_STACK_SIZE];
static StackType_t ConsumerTaskStack2[PRODUCER_TASK_STACK_SIZE];
/* Statically allocated memory for consumer_task task control block */
static StaticTask_t ConsumerTaskTCB0;
static StaticTask_t ConsumerTaskTCB1;
static StaticTask_t ConsumerTaskTCB2;
    TaskHandle = xTaskCreateStatic(producer_task, "PRODUCER_TASK", PRODUCER_TASK_STACK_SIZE, NULL, TASK_PRIO,
&(ProducerTaskStack[0]), &ProducerTaskTCB);
    TaskHandle = xTaskCreateStatic(consumer_task, "CONSUMER_TASK_0", CONSUMER_TASK_STACK_SIZE, (void *)0, TASK_PRIO,
&(ConsumerTaskStack0[0]), &ConsumerTaskTCB0);
创建Semaphore信号量的函数的参数也有不同。
sem例程通过栈Stack动态创建Semaphore信号量:
    xSemaphore_producer = xSemaphoreCreateBinary();
    xSemaphore_consumer = xSemaphoreCreateBinary();
sem_static例程通过静态声明变量并创建Semaphore信号量:
/* Statically allocated memory for producer semaphore structure */
static StaticSemaphore_t ProducerSemaphoreBuffer;
/* Statically allocated memory for consumer semaphore structure */
static StaticSemaphore_t ConsumerSemaphoreBuffer;
    xSemaphore_producer = xSemaphoreCreateBinaryStatic(&ProducerSemaphoreBuffer);
    xSemaphore_consumer = xSemaphoreCreateBinaryStatic(&ConsumerSemaphoreBuffer);
最终的运行效果sem_static和sem例程完全一致。
213  IMX-RT1052_SDK_freertos_sem_static例程的运行效果图
2.7 freertos_swtimer范例学习
Software_Timer软件定时器是FreeRTOS提供的一个定时服务,通过xTimerCreate()创建一个定时器,并设置回调函数SwTimerCallback(),执行定时循环程序。
int main(void)
{
    TimerHandle_t SwTimerHandle = NULL;
/* Init board hardware. */
    BOARD_ConfigMPU();
    BOARD_InitPins();
    BOARD_BootClockRUN();
    BOARD_InitDebugConsole();
    SystemCoreClockUpdate();
/* Create the software timer. */
    SwTimerHandle = xTimerCreate("SwTimer", /* Text name. */
                                 SW_TIMER_PERIOD_MS, /* Timer period. */
                                 pdTRUE, /* Enable auto reload. */
0, /* ID is not used. */
                                 SwTimerCallback); /* The callback function. */
/* Start timer. */
    xTimerStart(SwTimerHandle, 0);
/* Start scheduling. */
    vTaskStartScheduler();
for (;;)
;
}
/*!
* @brief Software timer callback.
*/
static void SwTimerCallback(TimerHandle_t xTimer)
{
    PRINTF("Tick.\r\n");
}
完成编译后下载调试,点击运行即可串口输出相关信息。
214  IMX-RT1052_SDK_freertos_swtimer例程的编译下载调试图
215  IMX-RT1052_SDK_freertos_swtimer例程的运行效果图
2.8 freertos_tickless
Tickless实现了FreeRTOS对低功耗的需求,通过关闭tick,停止了整个FreeRTOS的调度,只通过外部中断来实现唤醒。
程序首先注册了GPT中断和EXT外部按键中断的回调函数,分别为GPT1_IRQHandler()和BOARD_SW_IRQ_HANDLER()。
BOARD_SW_IRQ_HANDLER()提供信号量xSWSemaphore给SW_task,然后调度器调度执行SW_task,在其中获取xSWSemaphore,打印信息。然后继续等待下一个xSWSemaphore信号量。
/* Switch Task */
static void SW_task(void *pvParameters)
{
    xSWSemaphore = xSemaphoreCreateBinary();
for (;;)
{
if (xSemaphoreTake(xSWSemaphore, portMAX_DELAY) == pdTRUE)
{
            PRINTF("CPU waked up by EXT interrupt\r\n");
}
}
}
/*!
* @brief Interrupt service fuction of switch.
*
* This function to wake up CPU
*/
#ifdef BOARD_SW_NAME
void BOARD_SW_IRQ_HANDLER(void)
{
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
/* Clear external interrupt flag. */
#ifdef BOARD_SW_DELAY
volatile uint32_t i = 0;
for (i = 0; i < 10000000; ++i)
{
        __NOP(); /* delay */
}
    GPIO_PortClearInterruptFlags(BOARD_SW_GPIO, 1U << BOARD_SW_GPIO_PIN);
if (1 == GPIO_PinRead(BOARD_SW_GPIO, BOARD_SW_GPIO_PIN))
{
        xSemaphoreGiveFromISR(xSWSemaphore, &xHigherPriorityTaskWoken);
}
#else
    GPIO_PortClearInterruptFlags(BOARD_SW_GPIO, 1U << BOARD_SW_GPIO_PIN);
    xSemaphoreGiveFromISR(xSWSemaphore, &xHigherPriorityTaskWoken);
#endif
}
GPT1_IRQHandler()则调用vPortGptIsr(),该函数位于FreeRTOS\portable\low_power_tickless\fsl_tickless_gpt.c中,代码设置ulLPTimerInterruptFired=true,该条件触发FreeRTOS重新滴答Tick一次并调度。
void vPortGptIsr(void)
{
        ulLPTimerInterruptFired = true;
/* Clear interrupt flag.*/
        GPT_ClearStatusFlags(GPT1, kGPT_OutputCompare1Flag);
}
最后完成编译后下载调试,点击运行即可看到串口输出各类信息。
216  IMX-RT1052_SDK_freertos_tickless例程编译下载调试图
217  IMX-RT1052_SDK_freertos_tickless例程编运行效果图
注:该例程运行后,CPU进入低功耗模式,导致下一次下载调试会出现Invalid ROM Table错误。此时重启开发板并进入Serial Download模式即可重新下载调试。
回复 支持 反对

使用道具 举报

该用户从未签到

16

主题

107

帖子

2

中级会员

Rank: 3Rank: 3

积分
365
最后登录
2022-12-14
 楼主| 发表于 2018-11-10 12:53:28 | 显示全部楼层
2.9 freertos_generic范例学习
Freertos_generic例程提供了对FreeRTOS的Task、Queue、Semaphore、Timer等多种系统服务组件的综合使用示范。

2.9.1 消息队列与任务管理
该例程通过创建一个xQueue队列消息,来实现队列消息通讯机制。

/* Create the queue used by the queue send and queue receive tasks. */

    xQueue = xQueueCreate(/* The number of items the queue can hold. */

                          mainQUEUE_LENGTH,

/* The size of each item the queue holds. */

sizeof(uint32_t));

同时创建两个Task,一个Task循环延时后发送队列,另一个Task则持续监听队列,收到队列消息后则打印累计收到的队列消息数量。

/*!

* @brief Task prvQueueSendTask periodically sending message.

*/

static void prvQueueSendTask(void *pvParameters)

{

    TickType_t xNextWakeTime;

const uint32_t ulValueToSend = 100UL;

/* Initialise xNextWakeTime - this only needs to be done once. */

    xNextWakeTime = xTaskGetTickCount();

for (;;)

{

/* Place this task in the blocked state until it is time to run again.

        The block time is specified in ticks, the constant used converts ticks

        to ms.  While in the Blocked state this task will not consume any CPU

        time. */

        vTaskDelayUntil(&xNextWakeTime, mainQUEUE_SEND_PERIOD_MS);

/* Send to the queue - causing the queue receive task to unblock and

        increment its counter.  0 is used as the block time so the sending

        operation will not block - it shouldn't need to block as the queue

        should always be empty at this point in the code. */

        xQueueSend(xQueue, &ulValueToSend, 0);

}

}

/*!

* @brief Task prvQueueReceiveTask waiting for message.

*/

static void prvQueueReceiveTask(void *pvParameters)

{

uint32_t ulReceivedValue;

for (;;)

{

/* Wait until something arrives in the queue - this task will block

        indefinitely provided INCLUDE_vTaskSuspend is set to 1 in

        FreeRTOSConfig.h. */

        xQueueReceive(xQueue, &ulReceivedValue, portMAX_DELAY);

/*  To get here something must have been received from the queue, but

        is it the expected value?  If it is, increment the counter. */

if (ulReceivedValue == 100UL)

{

/* Count the number of items that have been received correctly. */

            ulCountOfItemsReceivedOnQueue++;

            PRINTF("Receive message counter: %d.\r\n", ulCountOfItemsReceivedOnQueue);

}

}

}

2.9.2 信号量消息管理
创建一个信号量xEventSemaphore。

/* Create the semaphore used by the FreeRTOS tick hook function and the

    event semaphore task. */

    vSemaphoreCreateBinary(xEventSemaphore);

并在vApplicationTickHook函数中发送信号量,该函数每次系统的滴答tick中都调用一次。

/*!

* @brief tick hook is executed every tick.

*/

void vApplicationTickHook(void)

{

    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

static uint32_t ulCount = 0;

/* The RTOS tick hook function is enabled by setting configUSE_TICK_HOOK to

    1 in FreeRTOSConfig.h.

    "Give" the semaphore on every 500th tick interrupt. */

    ulCount++;

if (ulCount >= 500UL)

{

/* This function is called from an interrupt context (the RTOS tick

        interrupt),    so only ISR safe API functions can be used (those that end

        in "FromISR()".

        xHigherPriorityTaskWoken was initialised to pdFALSE, and will be set to

        pdTRUE by xSemaphoreGiveFromISR() if giving the semaphore unblocked a

        task that has equal or higher priority than the interrupted task. */

        xSemaphoreGiveFromISR(xEventSemaphore, &xHigherPriorityTaskWoken);

        ulCount = 0UL;

}

/* If xHigherPriorityTaskWoken is pdTRUE then a context switch should

    normally be performed before leaving the interrupt (because during the

    execution of the interrupt a task of equal or higher priority than the

    running task was unblocked).  The syntax required to context switch from

    an interrupt is port dependent, so check the documentation of the port you

    are using.

    In this case, the function is running in the context of the tick interrupt,

    which will automatically check for the higher priority task to run anyway,

    so no further action is required. */

}

最后创建一个接受信号量的任务,该任务持续监听信号量,并输出信息。

/*!

* @brief task prvEventSemaphoreTask is waiting for semaphore.

*/

static void prvEventSemaphoreTask(void *pvParameters)

{

for (;;)

{

/* Block until the semaphore is 'given'. */

        xSemaphoreTake(xEventSemaphore, portMAX_DELAY);

/* Count the number of times the semaphore is received. */

        ulCountOfReceivedSemaphores++;

        PRINTF("Event task is running.\r\n");

}

}

2.9.3 定时器管理
创建一个xExampleSoftwareTimer的定时器,周期为mainSOFTWARE_TIMER_PERIOD_MS,定时器触发时调用vExampleTimerCallback()函数。

/* Create the software timer as described in the comments at the top of

    this file. */

    xExampleSoftwareTimer = xTimerCreate(/* A text name, purely to help

                                       debugging. */

"LEDTimer",

/* The timer period, in this case

                                         1000ms (1s). */

                                         mainSOFTWARE_TIMER_PERIOD_MS,

/* This is a periodic timer, so

                                         xAutoReload is set to pdTRUE. */

                                         pdTRUE,

/* The ID is not used, so can be set

                                         to anything. */

(void *)0,

/* The callback function that switches

                                         the LED off. */

                                         vExampleTimerCallback);

/* Start the created timer.  A block time of zero is used as the timer

    command queue cannot possibly be full here (this is the first timer to

    be created, and it is not yet running). */

    xTimerStart(xExampleSoftwareTimer, 0);

在vExampleTimerCallback()函数中,对定时器触发次数进行累计计数。

/*!

* @brief Timer callback.

*/

static void vExampleTimerCallback(TimerHandle_t xTimer)

{

/* The timer has expired.  Count the number of times this happens.  The

    timer that calls this function is an auto re-load timer, so it will

    execute periodically. */

    ulCountOfTimerCallbackExecutions++;

}

最后完成编译后下载调试,点击运行即可看到串口输出各类信息。并且IAR中显示对FreeRTOS系统内部Task、Queue等信息。

wpsE2ED.tmp

图 218  IMX-RT1052_SDK_freertos_generic例程编译下载调试图

wpsE2EE.tmp

图 219  IMX-RT1052_SDK_freertos_generic例程运行效果图

3
未完待续(TODO)
1、完成FreeRTOS的UART、I2C、SPI例程的运行。

2、使用IAR调试FreeRTOS例程,借助IAR的FreeRTOS插件,查看例程中的FreeRTOS运行状态如Task、Event等信息。

4 版本历史(Revision History)
版本号

发布时间

内容

A0

2018-11-10

初次编写
回复 支持 反对

使用道具 举报

  • TA的每日心情

    2021-2-4 09:24
  • 签到天数: 190 天

    [LV.7]常住居民III

    38

    主题

    591

    帖子

    28

    金牌会员

    Rank: 6Rank: 6

    积分
    2193
    最后登录
    2023-12-1
    发表于 2018-11-10 13:20:10 | 显示全部楼层
    谢谢分享,好东西
    哎...今天够累的,签到来了~
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    前天 08:28
  • 签到天数: 1313 天

    [LV.10]以坛为家III

    124

    主题

    2825

    帖子

    31

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    7552
    最后登录
    2024-3-27
    发表于 2018-11-10 15:54:56 | 显示全部楼层
    谢谢分享,学习下
    哎...今天够累的,签到来了~
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    慵懒
    2021-12-23 09:57
  • 签到天数: 1587 天

    [LV.Master]伴坛终老

    5

    主题

    3046

    帖子

    23

    金牌会员

    Rank: 6Rank: 6

    积分
    8183
    最后登录
    2024-3-28
    发表于 2018-11-12 10:05:49 | 显示全部楼层
    谢谢分享!
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-3-29 19:55 , Processed in 0.158111 second(s), 26 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表