最近使用一款STM32F4系列单片机做项目,计划把Threadx引入到其中.正好STM32CubeMX现在也可以直接生成Threadx工程初始代码.一开始不顺利,任务只能执行一次,经过对比研究发现问题,特此记录一下.
一,软件开发测试环境:
- STM32CubeMX:6.4.0;
- KEIL MDK-ARM:Community 5.37.0.0;
- STM32CubeF4 Firmware Package:1.27.0;
- X-CUBE-AZRTOS-F4:1.0.0;
- Threadx:6.1.7
二,硬件开发平台:
- STM32F4-Discovery(STM32F407VGT)
三,具体步骤:
-
选Threadx,如没有安装可以直接点Install安装;
-
激活Threadx选项,只选Core就可以,这里勾选其他两项是为了学习;
-
简单配置一下threadx,便于计算;
-
配置systick,根据STM32官方建议更改;
-
配置优先级分组,前几次一直不能成功的原因就是这里没选合适,要选4;
这里引用ARMFLY的说明:强烈推荐用户将 Cortex-M3 内核的 STM32F103 和 Cortex-M4 内核的 STM32F407 以及STM32F429 的 NVIC 优先级分组设置为 4,即:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);这样中断优先级的管理将非常方便.这个也是官方强烈建议的.
-
生成代码,打开Keil ARM MDK;
-
修改app_azure_rtos.c并编译;
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file app_azure_rtos.c
* @author MCD Application Team
* @brief azure_rtos application implementation file
******************************************************************************
* @attention
*
* Copyright (c) 2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "app_azure_rtos.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "main.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN TX_Pool_Buffer */
/* USER CODE END TX_Pool_Buffer */
static UCHAR tx_byte_pool_buffer[TX_APP_MEM_POOL_SIZE];
static TX_BYTE_POOL tx_app_byte_pool;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
#define APP_CFG_TASK_START_PRIO 10U
#define APP_CFG_TASK_START_STK_SIZE 4096u
TX_THREAD AppTaskStartTCB;
uint64_t AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE/8];
void AppTaskStart(ULONG thread_input);
/* USER CODE END PFP */
/**
* @brief Define the initial system.
* @param first_unused_memory : Pointer to the first unused memory
* @retval None
*/
VOID tx_application_define(VOID *first_unused_memory)
{
/* USER CODE BEGIN tx_application_define */
/* USER CODE END tx_application_define */
VOID *memory_ptr;
if (tx_byte_pool_create(&tx_app_byte_pool, "Tx App memory pool", tx_byte_pool_buffer, TX_APP_MEM_POOL_SIZE) != TX_SUCCESS)
{
/* USER CODE BEGIN TX_Byte_Pool_Error */
/* USER CODE END TX_Byte_Pool_Error */
}
else
{
/* USER CODE BEGIN TX_Byte_Pool_Success */
/* USER CODE END TX_Byte_Pool_Success */
memory_ptr = (VOID *)&tx_app_byte_pool;
if (App_ThreadX_Init(memory_ptr) != TX_SUCCESS)
{
/* USER CODE BEGIN App_ThreadX_Init_Error */
/* USER CODE END App_ThreadX_Init_Error */
}
/* USER CODE BEGIN App_ThreadX_Init_Success */
/*创建启动任务*/
tx_thread_create(&AppTaskStartTCB, /*任务控制块地址*/
"App Task Start", /*任务名*/
AppTaskStart, /*启动任务函数地址*/
0, /*传递给任务的参数*/
&AppTaskStartStk[0], /*堆栈基地址*/
APP_CFG_TASK_START_STK_SIZE, /*堆栈空间大小*/
APP_CFG_TASK_START_PRIO, /*任务优先级*/
APP_CFG_TASK_START_PRIO, /*任务抢占阈值*/
TX_NO_TIME_SLICE, /*不开启时间片*/
TX_AUTO_START); /*创建后立即启动*/
/* USER CODE END App_ThreadX_Init_Success */
}
}
/* USER CODE BEGIN 0 */
/*
*************************************************************
* 函 数 名:AppTaskStart
* 功能说明:启动任务
* 形 参:thread_input 是在创建该任务时传递的形参
* 返 回 值:无
* 优 先 级:2
************************************************************
*/
uint32_t uiCount = 0;
void AppTaskStart(ULONG thread_input)
{
(void)thread_input;
while(1)
{
uiCount++;
HAL_GPIO_TogglePin(LD3_GPIO_Port,LD3_Pin);
tx_thread_sleep(500);
HAL_GPIO_TogglePin(LD4_GPIO_Port,LD4_Pin);
tx_thread_sleep(500);
HAL_GPIO_TogglePin(LD6_GPIO_Port,LD6_Pin);
tx_thread_sleep(500);
HAL_GPIO_TogglePin(LD5_GPIO_Port,LD5_Pin);
tx_thread_sleep(500);
}
}
/* USER CODE END 0 */
-
通过查看开发版上LD3-LD6的状态或在debug模式下watch一下uiCount的值大约每2秒增加1来验证生成ThreadX工程是否正确;
接下来就可以简单方便的在STM32F4系列单片机上学习和使用ThreadX了.
2022/5/26补充
此步骤是依据安富莱ARMFLY的使用STM32CubeMX给STM32H7系列生成代码的视频写的,视频中硬汉哥仅仅演示这个过程.这几天我看了看STM32的threadx实例代码发现,用户任务代码都是放在Application/User/Core目录下的app_threadx.c文件中.建议新手还是把自己的任务放在app_threadx.c中,这样感觉要规范一些.