manhuami2007 发表于 2023-1-27 16:31

[ ST NUCLEO-U575ZI-Q 测评] 12-使用AZure ThreadX操作系统创建一个任务

<div class='showpostmsg'><p data-line="0" dir="auto">对于STM32U5芯片,在STM32CUBEMX中已经不支持生成FreeRTOS的代码了,而是使用Azure ThreadX操作系统。</p>

<p data-line="2" dir="auto">ThreadX是微软旗下的嵌入式操作系统,除了操作系统,还提供了多个组件,比如文件系统FileX,usb库USBX等等。相当于提供了一个全家桶,这样估计能够降低ST公司的代码维护难度吧,所以ST投向了微软。</p>

<p data-line="4" dir="auto">从现有版本的STM32CUBEMX中可以看到其它芯片还是支持FreeRTOS的,比如G0、F1、F4等。想要使用ThreadX系统的话,需要在CUBEMX上安装软件包。</p>

<h3 data-line="6" dir="auto" id="threadx%E7%AE%80%E4%BB%8B">ThreadX简介</h3>

<p data-line="8" dir="auto">ThreadX是一款工业级的实时操作系统,专门为深度嵌入式实时IOT应用程序设计。代码经过了多个安全认证。主要使用ANSI C编写。内核代码是开源的。在视频中看到在STM32中使用Azure全家桶都是免费的。ThreadX占用的ROM在2KB-20KB,占用的RAM在1-2KB。</p>

<h3 data-line="10" dir="auto" id="cubemx%E4%B8%AD%E8%AE%BE%E7%BD%AE%E9%A1%B9%E7%9A%84%E6%84%8F%E4%B9%89">CUBEMX中设置项的意义</h3>

<p data-line="12" dir="auto">在cubemx中能看到有很多的设置项,其中一部分的意义分别如下:</p>

<ul data-line="14" dir="auto">
        <li data-line="14" dir="auto">
        <p data-line="14" dir="auto">TX_MINIMUM_STACK:定义最小堆栈大小(以字节为单位)。 它用于在创建线程时进行错误检查。 默认值是端口特定的,位于 tx_port.h 中。</p>
        </li>
        <li data-line="16" dir="auto">
        <p data-line="16" dir="auto">TX_THREAD_USER_EXTENSION</p>
        </li>
        <li data-line="18" dir="auto">
        <p data-line="18" dir="auto">TX_DISABLE_STACK_FILLING:定义后,禁止在创建时将 0xEF 值置于每个线程的堆栈的每个字节中。 默认情况下,未定义此选项。</p>
        </li>
        <li data-line="20" dir="auto">
        <p data-line="20" dir="auto">TX_DISABLE_PREEMPTION_THRESHOLD:定义后,将禁用抢占阈值功能,并略微减少代码大小并提高性能。 当然,抢占阈值功能不再可用。 默认情况下,未定义此选项。</p>
        </li>
        <li data-line="22" dir="auto">
        <p data-line="22" dir="auto">TX_DISABLE_REDUNDANT_CLEARING:定义后,删除用于将 ThreadX 全局 C 数据结构初始化为零的逻辑。 仅当编译器的初始化代码将所有未初始化的 C 全局数据设置为零时,才应使用此选项。 在初始化期间,使用此选项可以略微减少代码大小并提高性能。 默认情况下,未定义此选项。</p>
        </li>
        <li data-line="24" dir="auto">
        <p data-line="24" dir="auto">TX_DISABLE_NOTIFY_CALLBACKS:定义后,将对各种 ThreadX 对象禁用通知回调。 使用此选项可以略微减少代码大小并提高性能。 默认情况下,未定义此选项。</p>
        </li>
        <li data-line="26" dir="auto">
        <p data-line="26" dir="auto">TX_INLINE_THREAD_RESUME_SUSPEND:定义后,ThreadX 通过行内代码改进 tx_thread_resume 和 tx_thread_suspend API 调用。 这会增加代码大小,但会增强这两个 API 调用的性能。</p>
        </li>
        <li data-line="28" dir="auto">
        <p data-line="28" dir="auto">TX_NOT_INTERRUPTABLE:定义后,ThreadX 不会尝试最大程度地缩短中断锁定时间。 这会提升执行速度,但会略微增加中断锁定时间。</p>
        </li>
        <li data-line="30" dir="auto">
        <p data-line="30" dir="auto">TX_MAX_PRIORITIES:定义 ThreadX 的优先级别。 合法值的范围为 32 到 1024(含),且必须能被 32 整除。 增加支持的优先级别数量会使每组 32 个优先级别的 RAM 用量增加 128 字节。 但是,对性能的影响可忽略不计。 默认情况下,此值设置为 32 个优先级别。</p>
        </li>
        <li data-line="32" dir="auto">
        <p data-line="32" dir="auto">TX_ENABLE_EXECUTION_CHANGE_NOTIFY</p>
        </li>
        <li data-line="34" dir="auto">
        <p data-line="34" dir="auto">TX_THREAD_GET_SYSTEM_STATE:定义一个宏用TX_THREAD_GET_SYSTEM_STATE()代替_tx_thread_system_state函数。</p>
        </li>
        <li data-line="36" dir="auto">
        <p data-line="36" dir="auto">TX_THREAD_SYSTEM_RETURN_CHECK (c):定义是否调用检查返回值的函数_tx_thread_system_return。</p>
        </li>
        <li data-line="38" dir="auto">
        <p data-line="38" dir="auto">TX_TIMER_TICKS_PER_SECOND:每秒的调度次数</p>
        </li>
        <li data-line="39" dir="auto">
        <p data-line="39" dir="auto">ALIGN_TYPE_DEFINED</p>
        </li>
        <li data-line="40" dir="auto">
        <p data-line="40" dir="auto">TX_MEMSET:将memset函数通过宏定义为TX_MEMSET函数</p>
        </li>
        <li data-line="41" dir="auto">
        <p data-line="41" dir="auto">TX_NO_FILEX_POINTER:是否使用FILEX的指针。</p>
        </li>
        <li data-line="42" dir="auto">
        <p data-line="42" dir="auto">Enable BASEPRI support</p>
        </li>
        <li data-line="43" dir="auto">
        <p data-line="43" dir="auto">TX_DISABLE_ERROR_CHECKING:跳过基本服务调用错误检查。 在应用程序源中定义时,将禁用所有基本参数错误检查。 这可能会将性能提高多达 30%,还可能会减小图像大小。</p>
        </li>
        <li data-line="45" dir="auto">
        <p data-line="45" dir="auto">TX_TIMER_PROCESS_IN_ISR:定义后,将消除 ThreadX 的内部系统计时器线程。 这会提升计时器事件和更小 RAM 要求的性能,因为不再需要计时器堆栈和控制块。 但是,使用此选项会将所有计时器过期处理移动到计时器 ISR 级别。 默认情况下,未定义此选项。</p>
        </li>
        <li data-line="47" dir="auto">
        <p data-line="47" dir="auto">TX_REACTIVATE_INLINE:确定是否应在计时器过期处理中使用内嵌计时器重新激活。默认情况下,这是禁用的,并使用函数调用。当定义了以下内容时,重新激活将inline执行,从而加快计时器处理速度,但代码大小略大。</p>
        </li>
        <li data-line="49" dir="auto">
        <p data-line="49" dir="auto">TX_TIMER_THREAD_STACK_SIZE:定义内部 ThreadX 系统计时器线程的堆栈大小(以字节为单位)。 此线程处理所有线程睡眠请求以及所有服务调用超时。 此外,从该上下文调用所有应用程序计时器回调例程。 默认值是端口特定的,位于 tx_port.h 中。</p>
        </li>
        <li data-line="51" dir="auto">
        <p data-line="51" dir="auto">TX_TIMER_THREAD_PRIORITY:定义内部 ThreadX 系统计时器线程的优先级。 默认值为优先级 0 - ThreadX 中的最高优先级。 默认值在 tx_port.h 中定义。</p>
        </li>
</ul>

<h3 data-line="53" dir="auto" id="%E5%B8%B8%E7%94%A8%E7%9A%84%E8%AE%BE%E7%BD%AE%E9%A1%B9">常用的设置项</h3>

<p data-line="55" dir="auto">官网上也给出了对于追求速度或者追求最小内存空间应该使用的设置项。</p>

<p data-line="57" dir="auto">追求速度应定义以下宏:</p>

<ul data-line="58" dir="auto">
        <li data-line="58" dir="auto">TX_MAX_PRIORITIES 32</li>
        <li data-line="59" dir="auto">TX_DISABLE_PREEMPTION_THRESHOLD</li>
        <li data-line="60" dir="auto">TX_DISABLE_REDUNDANT_CLEARING</li>
        <li data-line="61" dir="auto">TX_DISABLE_NOTIFY_CALLBACKS</li>
        <li data-line="62" dir="auto">TX_NOT_INTERRUPTABLE</li>
        <li data-line="63" dir="auto">TX_TIMER_PROCESS_IN_ISR</li>
        <li data-line="64" dir="auto">TX_REACTIVATE_INLINE</li>
        <li data-line="65" dir="auto">TX_DISABLE_STACK_FILLING</li>
        <li data-line="66" dir="auto">TX_INLINE_THREAD_RESUME_SUSPEND</li>
</ul>

<p data-line="68" dir="auto">追求最小内存空间应定义以下宏:</p>

<ul data-line="69" dir="auto">
        <li data-line="69" dir="auto">TX_MAX_PRIORITIES 32</li>
        <li data-line="70" dir="auto">TX_DISABLE_PREEMPTION_THRESHOLD</li>
        <li data-line="71" dir="auto">TX_DISABLE_REDUNDANT_CLEARING</li>
        <li data-line="72" dir="auto">TX_DISABLE_NOTIFY_CALLBACKS</li>
        <li data-line="73" dir="auto">TX_NOT_INTERRUPTABLE</li>
        <li data-line="74" dir="auto">TX_TIMER_PROCESS_IN_ISR</li>
</ul>

<h3 data-line="76" dir="auto" id="%E6%8A%A2%E5%8D%A0%E9%98%88%E5%80%BC">抢占阈值</h3>

<p data-line="78" dir="auto">这个名次在其它RTOS中没听过。这个阈值的目的是防止不同优先级的线程间过度抢占。可以设置一个阈值,比如优先级20的线程,设置抢占式阈值为15,那么优先级比15低的都不会和这个线程发生抢占。</p>

<h3 data-line="80" dir="auto" id="tx_disable_stack_filling%E7%9A%84%E4%BD%9C%E7%94%A8">TX_DISABLE_STACK_FILLING的作用</h3>

<p data-line="82" dir="auto">这个宏的作用是填充堆栈为0xEF。为什么要填充为0xEF呢?</p>

<p data-line="84" dir="auto">这个是为了确认堆栈的使用上限位置的。设置多大的堆栈是有关线程的最常见问题之一。调试应用程序后,如果内存不足,可以调整线程堆栈大小。常用的技巧是在创建线程之前,使用诸如 (0xEFEF) 之类易于识别的数据模式预设所有堆栈区域。 在应用程序经过全面测试后,可以对堆栈区域进行检查,具体方法是通过查找堆栈区域(其中的数据模式仍保持不变)来查看实际使用了多少堆栈。 下图显示了堆栈在线程完全执行后预设为 0xEFEF。</p>

<p data-line="86" dir="auto"></p>

<h3 data-line="88" dir="auto" id="%E7%BA%BF%E7%A8%8B%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7">线程的优先级</h3>

<p data-line="90" dir="auto">数值越小,优先级越高。 因此,优先级 0 表示最高优先级,而优先级 (TX_MAX_PRIORITIES-1) 表示最低优先级。</p>

<h3 data-line="92" dir="auto" id="rtos%E7%9A%84%E5%85%A5%E5%8F%A3%E4%BD%8D%E7%BD%AE">RTOS的入口位置</h3>

<p data-line="94" dir="auto">main 函数调用 tx_kernel_enter,这是 ThreadX 的入口。entry 函数协调各种内部 ThreadX 数据结构的初始化,然后调用应用程序的定义函数 tx_application_define。当 tx_application_define 返回时,控制权将转交给线程调度循环。 这标志着初始化结束。</p>

<p data-line="96" dir="auto">tx_application_define函数位于&quot;app_azure_rtos.c&quot;文件中。这个函数再调用App_ThreadX_Init函数,这个函数位于&quot;app_threadx.c&quot;中,因此我们应该在这个函数中定义各个任务、用到的消息等系统资源。</p>

<h3 data-line="98" dir="auto" id="%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E7%9A%84%E6%96%B9%E6%B3%95">创建一个线程的方法</h3>

<p data-line="100" dir="auto">创建一个线程需要:</p>

<ol data-line="101" dir="auto">
        <li data-line="101" dir="auto">线程控制块</li>
        <li data-line="102" dir="auto">栈空间</li>
        <li data-line="103" dir="auto">入口函数</li>
        <li data-line="104" dir="auto">调用tx_thread_create函数,创建线程</li>
</ol>

<p data-line="106" dir="auto">tx_thread_create的函数原型为</p>

<pre>
<code>UINT tx_thread_create(
    TX_THREAD *thread_ptr,
    CHAR *name_ptr,
    VOID (*entry_function)(ULONG),
    ULONG entry_input,
    VOID *stack_start,
    ULONG stack_size,
    UINT priority,
    UINT preempt_threshold,
    ULONG time_slice,
    UINT auto_start);</code></pre>

<p data-line="121" dir="auto">代码如下:</p>

<pre>
<code>uint32_t thread0_stack;//线程的栈空间
TX_THREAD thread_0;
void thread_0_entry(ULONG thread_input) //线程的入口函数
{
while(1){
    HAL_GPIO_TogglePin(LED_BLUE_GPIO_Port,LED_BLUE_Pin);
    tx_thread_sleep(50);
}
}

UINT App_ThreadX_Init(VOID *memory_ptr) //在这个函数里添加创建线程的代码
{
UINT ret = TX_SUCCESS;
TX_BYTE_POOL *byte_pool = (TX_BYTE_POOL*)memory_ptr;

   /* USER CODE BEGIN App_ThreadX_MEM_POOL */
(void)byte_pool;
/* USER CODE END App_ThreadX_MEM_POOL */

/* USER CODE BEGIN App_ThreadX_Init */
tx_thread_create(&amp;thread_0,"thread0",thread_0_entry,0,thread0_stack,1024,10,10,0,TX_AUTO_START ); //创建线程
/* USER CODE END App_ThreadX_Init */

return ret;
}</code></pre>

<p data-line="150" dir="auto">通过上面的代码就可以创建1个线程,没500ms翻转一次LED。</p>

<p data-line="152" dir="auto">这是参考资料的链接&nbsp;<a data-href="https://learn.microsoft.com/zh-cn/azure/rtos/threadx/about-this-guide" href="https://learn.microsoft.com/zh-cn/azure/rtos/threadx/about-this-guide">ThreadX指南</a>。</p>

<p>https://learn.microsoft.com/zh-cn/azure/rtos/threadx/about-this-guide</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

wangerxian 发表于 2023-1-28 13:22

<p>不支持FreeRTOS了?只是这个型号不支持了吧。</p>

manhuami2007 发表于 2023-1-28 13:31

wangerxian 发表于 2023-1-28 13:22
不支持FreeRTOS了?只是这个型号不支持了吧。

<p>后续新的芯片都不支持freertos了。</p><br/><p>azure&nbsp;threadx能够封装成兼容freertos的程序</p><br/>

wangerxian 发表于 2023-1-28 17:36

manhuami2007 发表于 2023-1-28 13:31
后续新的芯片都不支持freertos了。azure&nbsp;threadx能够封装成兼容freertos的程序

<p>azure&nbsp;threadx更有优势?让ST这么选择。</p>

manhuami2007 发表于 2023-1-28 19:40

wangerxian 发表于 2023-1-28 17:36
azure&nbsp;threadx更有优势?让ST这么选择。

<p>azure&nbsp;有全家桶,包括文件系统,网络通信协议,usb等等。不用像freertos那样,需要第三方的库函数去拼凑。而且用azure的话,我觉得也降低了st对库函数的维护工作量。所以st这么选吧,我觉得单纯对比freertos和azure&nbsp;threax的话,两个也没有什么太大的区别。</p><br/>

wangerxian 发表于 2023-1-29 09:14

manhuami2007 发表于 2023-1-28 19:40
azure&nbsp;有全家桶,包括文件系统,网络通信协议,usb等等。不用像freertos那样,需要第三方的库函数去 ...

<p>明白了,有时间我也看看去。</p>

okhxyyo 发表于 2023-2-2 14:09

<p>测评汇总:免费申请|ST NUCLEO-U575ZI-Q https://bbs.eeworld.com.cn/thread-1228653-1-1.html</p>
页: [1]
查看完整版本: [ ST NUCLEO-U575ZI-Q 测评] 12-使用AZure ThreadX操作系统创建一个任务