STM32CubeMX为STM32F4系列生成ThreadX初始代码

867 阅读3分钟

最近使用一款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)

三,具体步骤:

  1. 选Threadx,如没有安装可以直接点Install安装;

image.png

  1. 激活Threadx选项,只选Core就可以,这里勾选其他两项是为了学习;

image.png

  1. 简单配置一下threadx,便于计算;

image.png

  1. 配置systick,根据STM32官方建议更改;

image.png

  1. 配置优先级分组,前几次一直不能成功的原因就是这里没选合适,要选4;

这里引用ARMFLY的说明:强烈推荐用户将 Cortex-M3 内核的 STM32F103 和 Cortex-M4 内核的 STM32F407 以及STM32F429 的 NVIC 优先级分组设置为 4,即:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);这样中断优先级的管理将非常方便.这个也是官方强烈建议的.

image.png

  1. 生成代码,打开Keil ARM MDK;

  2. 修改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 */
  1. 通过查看开发版上LD3-LD6的状态或在debug模式下watch一下uiCount的值大约每2秒增加1来验证生成ThreadX工程是否正确;

image.png

接下来就可以简单方便的在STM32F4系列单片机上学习和使用ThreadX了.


2022/5/26补充

此步骤是依据安富莱ARMFLY的使用STM32CubeMX给STM32H7系列生成代码的视频写的,视频中硬汉哥仅仅演示这个过程.这几天我看了看STM32的threadx实例代码发现,用户任务代码都是放在Application/User/Core目录下的app_threadx.c文件中.建议新手还是把自己的任务放在app_threadx.c中,这样感觉要规范一些.