STM32F429第3章 ThreadX USBX协议栈移植到STM32F429

Posted 安富莱电子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32F429第3章 ThreadX USBX协议栈移植到STM32F429相关的知识,希望对你有一定的参考价值。

教程更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=108546

第3章   ThreadX USBX协议栈移植到STM32F429

本章节为大家讲解USBX协议栈移植到STM32F429。

3.1 初学者重要提示

3.2 USBX移植步骤

3.3 USBX的模拟U盘移植接口文件ux_device_msc.c。

3.4 使用的MicroUSB接口并注意跳线帽设置

3.5 实验例程

3.6 总结

 

 

3.1   初学者重要提示

1、  本章使用的ST专门为STM32F4提供的软件包:

http://www.armbbs.cn/forum.php?mod=viewthread&tid=108636 .

2、  本章配套例子使用SD卡模拟一个U盘,使用的MicroUSB接口。

3.2   USBX移植步骤

ThreadX USBX的移植步骤如下:

3.2.1      第1步,了解整体设计框架

为了方便大家移植,需要大家先对移植好的工程有个整体认识:

 

 

3.2.2      第2步,添加USBX和USB驱动到工程

这里我们在FileX教程做的模板例子基础上添加USBX文件和USB驱动文件,大家可以直接从本章教程提供的例子里面复制。

  •   模拟U盘驱动文件ux_device_msc.c/.h和ux_device_descriptors.c/.h添加到自己的工程里面,路径不限。

配套例子是放在\\User\\usb文件。

  •   USB驱动文件stm32f4xx_hal_hcd.c,stm32f4xx_hal_pcd.c,stm32f4xx_hal_pcd_ex.c和stm32f4xx_ll_usb.c。

这个是STM32F4的HAL库自带的。

  •   USBX相关源文件。

大家可以将所有相关文件都复制到自己的工程里面,配套例子是放在\\USBX。

3.2.3      第3步,添加工程路径

大家根据自己添加的源文件位置,添加相关路径即可:

 

 

3.2.4      第4步,禁止掉添加进来一些文件

之所以要禁止掉是因为这些文件要用到NetXDUO网络协议栈,或者大家不添加进来都是可以的。添加进来后再禁止的优势是添加时候可以全选添加。

 

 

禁止的方法是右击此文件去掉如下对钩即可:

 

 

3.2.5      第4步,配置GPIO和时钟

USB时钟配置在bsp.c文件的函数SystemClock_Config里面:

    /* 芯片内部的LDO稳压器输出的电压范围,选用的PWR_REGULATOR_VOLTAGE_SCALE1 */
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    /* 使能HSE,并选择HSE作为PLL时钟源 */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 8;
    RCC_OscInitStruct.PLL.PLLN = 336;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 7;  这个分频很重要,分频出48MHz
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler(__FILE__, __LINE__);
    }

USB的GPIO,NVIC初始化在demo_sd_usbx.c:

    /* 配置USB GPIO, NVIC */
    {
        GPIO_InitTypeDef  GPIO_InitStruct = {0};

        __HAL_RCC_GPIOA_CLK_ENABLE();

        GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_11;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
        

        /* 使能USB FS时钟 */
        __HAL_RCC_USB_OTG_FS_CLK_ENABLE();

        
        /* 配置USB FS中断 */
        HAL_NVIC_SetPriority(OTG_FS_IRQn, 0, 0); 
        HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
    }

    /* 初始化USB */
    {
        memset(&hpcd_USB_OTG_FS, 0x0, sizeof(PCD_HandleTypeDef));
      hpcd_USB_OTG_FS.Instance = USB_OTG_FS;
      hpcd_USB_OTG_FS.Init.dev_endpoints = 4;
      hpcd_USB_OTG_FS.Init.speed = PCD_SPEED_FULL;
      hpcd_USB_OTG_FS.Init.dma_enable = DISABLE;
      hpcd_USB_OTG_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
      hpcd_USB_OTG_FS.Init.Sof_enable = DISABLE;
      hpcd_USB_OTG_FS.Init.low_power_enable = DISABLE;
      hpcd_USB_OTG_FS.Init.lpm_enable = DISABLE;
      hpcd_USB_OTG_FS.Init.vbus_sensing_enable = DISABLE;
      hpcd_USB_OTG_FS.Init.use_dedicated_ep1 = DISABLE;

        /* 初始化USB  */
        HAL_PCD_Init(&hpcd_USB_OTG_FS);

        /* 设置TX FIFO和RX FIFO */
        HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_FS, 128);
        HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 64);
        HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 128);

        /* 注册STM32到USBX协议栈并初始化 */
        status =  ux_dcd_stm32_initialize((ULONG)USB_OTG_FS, (ULONG)&hpcd_USB_OTG_FS);

        if (status != FX_SUCCESS)
        {
            return;
        }
        
    }

3.2.6      第7步,添加应用代码(USB中断,打开U盘和关闭U盘)

USB操作专门整理到了文件demo_sd_usbx.c。主要三部分,打开U盘,关闭U盘和USB中断服务程序。这三个函数基本是通用的,大家直接复制粘贴使用即可

特别注意USB中断服务程序别忘了添加。

3.3   USBX的模拟U盘移植接口文件ux_device_msc.c说明

这里将USBX的底层接口文件ux_device_msc.c的实现为大家简单做个说明。

3.3.1  状态函数app_usb_device_thread_media_status

代码如下:

UINT  app_usb_device_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status)
{

  /* The ATA drive never fails. This is just for app_usb_device only !!!! */
  return (UX_SUCCESS);
}

此函数主要用于获取SD卡模拟U盘的状态。

3.3.2  读取函数app_usb_device_thread_media_read

代码如下:

/**
  * @brief  Function implementing app_usb_device_thread_media_read.
  * @param  storage : Not used
  * @param  lun: Logical unit number
  * @param  lba: Logical block address
  * @param  number_blocks: Blocks number
  * @param  data_pointer: Data
  * @param  media_status: Not used
  * @retval Status (0 : OK / -1 : Error)
  */
UINT  app_usb_device_thread_media_read(VOID *storage, ULONG lun,
                                       UCHAR *data_pointer,
                                       ULONG number_blocks,
                                       ULONG lba, ULONG *media_status)
{
#if 0
    UINT status = 0U;

    BSP_SD_ReadBlocks((uint32_t *) data_pointer, lba, number_blocks, 500);                                    
    status = check_sd_status(0);    
    return (status);

#else
    UINT status;
    if(check_sd_status(0) != BSP_ERROR_NONE)
    {
        
    }
    
    status = BSP_SD_ReadBlocks_DMA((uint32_t*)data_pointer, lba, number_blocks);

    if (status == BSP_ERROR_NONE)
    {
        if(tx_semaphore_get(&transfer_semaphore, DEFAULT_TIMEOUT) == TX_SUCCESS)
        {
            status = FX_SUCCESS;
        }
        else
        {
            status =  FX_BUFFER_ERROR;
        }
    }

    return status;
#endif
}

用于实现SD模拟U盘的读取功能。

3.3.3  写入函数app_usb_device_thread_media_write

代码如下:

/**
  * @brief  Function implementing app_usb_device_thread_media_write.
  * @param  storage : Not used
  * @param  lun: Logical unit number
  * @param  lba: Logical block address
  * @param  number_blocks: Blocks number
  * @param  data_pointer: Data
  * @param  media_status: Not used
  * @retval Status (0 : OK / -1 : Error)
  */
UINT  app_usb_device_thread_media_write(VOID *storage, ULONG lun,
                                        UCHAR *data_pointer,
                                        ULONG number_blocks,
                                        ULONG lba, ULONG *media_status)
{
#if 0
    UINT status = 0U;

    BSP_SD_WriteBlocks((uint32_t *) data_pointer, lba, number_blocks, 500);
    status = check_sd_status(0);
    
    return (status);

#else
    UINT status;
    
    if(check_sd_status(0) != BSP_ERROR_NONE)
    {
        
    }

    status = BSP_SD_ReadBlocks_DMA((uint32_t*)data_pointer, lba, number_blocks);

    if (status == BSP_ERROR_NONE)
    {
        if(tx_semaphore_get(&transfer_semaphore, DEFAULT_TIMEOUT) == TX_SUCCESS)
        {
            status = FX_SUCCESS;
        }
        else
        {
            status =  FX_BUFFER_ERROR;
        }
    }

#endif

    return status;
}

用于实现SD模拟U盘的写入功能。

3.3.4  接口函数注册

接口函数的注册是在文件demo_sd_usbx.c里面:

storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read  =  app_usb_device_thread_media_read;

storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write  =  app_usb_device_thread_media_write; 

storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status =  app_usb_device_thread_media_status;

3.4   使用的MicroUSB接口并注意跳线帽设置

本周教程移植的例子使用内部RAM模拟了一个U盘,效果如下:

 

 

注意使用的是MicroUSB接口:

 

 

注意板子左下角跳线帽的设置:

 

 

这里是用于选择CAN1 TX使用PB9或者PA12引脚,CAN1 RX使用PB8或者PA11引脚。大家这里可以什么都不接,或者CAN1 TX通过跳线帽短接PA12,CAN1 RX通过跳线帽短接PA11。切记不可以短接到PA12和PA11引脚上,USB要使用这两个引脚。

3.5   实验例程

配套例子:

V6-2401_ThreadX USBX Template

实验目的:

  1. 学习USBX模板,通过SD来模拟U盘。

实验内容:

1、共创建了如下几个任务,通过按下按键K1可以通过串口或者RTT打印任务堆栈使用情况                                  

========================================================

         CPU利用率 =  0.89%

         任务执行时间 = 0.586484645s

         空闲执行时间 = 85.504470575s

         中断执行时间 = 0.173225395s

         系统总执行时间 = 86.264180615s              

=======================================================

        任务优先级 任务栈大小 当前使用栈  最大栈使用   任务名

          Prio     StackSize   CurStack    MaxStack   Taskname

          2         4092        303         459      App Task Start

          5         4092        167         167      App Msp Pro

          4         4092        167         167      App Task UserIF

           5         4092        167         167      App Task COM

           0         1020        191         191      System Timer Thread           

串口软件可以使用SecureCRT或者H7-TOOL RTT查看打印信息。

App Task Start任务  :启动任务,这里用作BSP驱动包处理。

App Task MspPro任务 :消息处理。

App Task UserIF任务 :按键消息处理。

App Task COM任务   :这里用作LED闪烁。

System Timer Thread任务:系统定时器任务

2、(1) 凡是用到printf函数的全部通过函数App_Printf实现。

(2) App_Printf函数做了信号量的互斥操作,解决资源共享问题。

3、默认上电是通过串口打印信息,如果使用RTT打印信息

(1)   MDK AC5,MDK AC6或IAR通过使能bsp.h文件中的宏定义为1即可

#define Enable_RTTViewer  1

(2)   Embedded Studio继续使用此宏定义为0, 因为Embedded Studio仅制作了调试状态RTT方式查看。

实验操作:

  1. 测试前务必将SD卡插入到开发板左上角的卡座中。
  2. 支持以下6个功能,用户通过电脑端串口软件发送数字1-6给开发板即可
  3. printf("1 - 显示根目录下的文件列表\\r\\n");
  4. printf("2 - 创建一个新文件armfly.txt\\r\\n");
  5. printf("3 - 读armfly.txt文件的内容\\r\\n");
  6. printf("4 - 创建目录\\r\\n");
  7. printf("5 - 删除文件和目录\\r\\n");
  8. printf("6 - 读写文件速度测试\\r\\n");
  9. printf("a - 打开SD卡模拟U盘\\r\\n");
  10. printf("b - 关闭SD卡模拟U盘\\r\\n");

串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1

 

 

RTT打印:

 

 

3.6   总结

本章节就为大家讲解这么多,后面章节再为大家详细讲解USBX的玩法。

 

微信公众号:armfly_com 安富莱论坛:www.armbbs.cn 安富莱淘宝:https://armfly.taobao.com

STM32H7第22章 ThreadX动态内存管理

论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=99514

第22章       ThreadX动态内存管理

本章节为大家讲解ThreadX动态内存管理,ThreadX支持固定数据大小的内存块式分配,也支持类似C库的malloc方式分配。

目录

22.1 ThreadX内存块方式介绍

22.2 ThreadX内存字节池方式介绍

22.3 内存块创建函数tx_block_pool_create

22.4 内存块申请函数tx_block_allocate

22.5 内存块释放函数tx_block_release

22.6 内存池创建函数tx_byte_pool_create

22.7 内存池申请函数tx_byte_allocate

22.8 内存池释放函数tx_byte_release

22.9 内存池使用情况获取函数tx_byte_pool_info_get

22.10          实验例程

22.11          总结


22.1 ThreadX内存块方式介绍

在ANSI C中,可以用malloc()和free()动态的分配内存和释放内存,但是,在嵌入式实时操作系统中,调用malloc()和free()却是危险的,因为多次调用这两个函数会把原来很大的一块连续内场区域逐渐地分割成许多非常小而且彼此又不相邻的内存块,也就是内存碎片。由于这些内存碎片的大量存在,使得程序到后来连一段非常小的连续内存也分配不到。另外,由于内存管理算法上的原因,malloc()和free()函数的执行时间是不确定的。

在ThreadX内存块管理方式中,操作系统把连续的大块内存按分区来管理。每个分区中包含整数个大小相同的内存块:

 

利用这种机制,就可以得到和释放固定大小的内存块。这样内存的申请和释放函数的执行时间就是确定的了。

在一个系统中可以有多个内存分区,这样,应用程序就可以从不同的内存分区中得到不同大小的内存块。但是特定的内存块在释放时,必须重新放回到它以前所属的内存分区。显然,采用这样的内存管理算法,上面的内存碎片文件就得到了解决。

缺乏灵活性是固定大小内存块的主要缺点。块大小必须足够大,才能处理用户最坏情况下的内存需求。如果发出许多大小不同的内存请求,则可能会浪费内存。 一种可能的解决方案是创建多个不同的内存块。

22.2 ThreadX内存字节池方式介绍

ThreadX内存字节池与标准C库类似。不同之处在于,ThreadX的内存字节池支持多个不同内存区的创建管理。此外,任务可在池中挂起,直到请求的内存可用为止。

内存字节池的分配与传统的 malloc 调用类似,其中包含所需的内存量(以字节为单位)。内存采用“first-fit”的方式从池中分配;例如,使用满足请求的第一个可用内存块,此块中多余的内存会转换为新块,并放回可用内存列表中,此过程称为碎片。相邻的可用内存块在后续的分配搜索过程中合并为一个足够大的可用内存块。此过程称为碎片整理。

每个内存字节池都是一个公用资源。 除了不能从中断服务程序里面调用内存字节服务之外,ThreadX 对如何使用也没有任何限制。

22.3 内存块创建函数tx_block_pool_create

函数原型:

UINT tx_block_pool_create(
    TX_BLOCK_POOL pool_ptr,
    CHAR name_ptr, 
    ULONG block_size,
    VOID pool_start, 
    ULONG pool_size);

函数描述:

此函数用于内存块创建,内存块中每个内存单元的大小是固定。

函数参数:

  •   第1个参数是内存控制块。
  •   第2个参数是内存块名字。
  •   第3个参数是内存块中每个内存单元的大小。
  •   第4个参数是内存块起始地址,必须ULONG对齐,即4字节对齐。
  •   第5个参数是内存块总大小,单位字节。
  •   返回值
    • TX_SUCCESS (0x00) 创建成功。
    • TX_POOL_ERROR (0x02) 无效的内存控制块。或者内存块已经创建。又或者指针为NULL。
    • TX_PTR_ERROR (0x03) 表示无效的内存块地址。
    • TX_CALLER_ERROR (0x13) 表示无效的调用。
    • TX_SIZE_ERROR(0x05)表示无效的内存块大小。

注意事项:

  •   可以在初始化和任务中调用。
  •   总的内存单元个数是total blocks = (total bytes) / (block size + sizeof(void *))。

使用举例:

TX_BLOCK_POOL AppBlock;

uint32_t AppBlockBuf[1024];

/* 创建内存块,用于固定大小内存单元申请 */
tx_block_pool_create(&AppBlock,
        "AppBlock",
        4,                   /* 内存单元大小 */
      (VOID *)AppBlockBuf,  /* 内存块地址,需要保证4字节对齐 */
       sizeof(AppBlockBuf));/* 内存块总大小,单位字节 */    

22.4 内存块申请函数tx_block_allocate

函数原型:

UINT tx_block_allocate(
    TX_BLOCK_POOL *pool_ptr, 
    VOID **block_ptr,
    ULONG wait_option);

函数描述:

用于内存块申请,每次可申请一个内存单元。

函数参数:

  •   第1个参数是内存控制块。
  •   第2个参数用于存放申请的内存单元地址。
  •   第3个参数是没有可用的内存单元时执行方式,支持如下三种参数
    •   TX_NO_WAIT (0x00000000),表示不管是否获取成功,立即返回。如果在初始化阶段调用,必须要设置成这个参数。
    •   TX_WAIT_FOREVER (0xFFFFFFFF),表示永久等待,直到有内存单元可用。
    •   等待时间,范围0x00000001 到 0xFFFFFFFE,单位系统时钟节拍、
  •   返回值
    • TX_SUCCESS:(0x00) 成功分配内存块。
    • TX_DELETED:(0x01) 线程挂起时删除了内存块。
    • TX_NO_MEMORY:(0X10) 服务无法在指定的等待时间内分配内存块。
    • TX_WAIT_ABORTED:(0x1A) 挂起状态由其他线程、计时器或 ISR 中止。
    • TX_POOL_ERROR:(0x02) 内存块指针无效。
    • TX_WAIT_ERROR:(0x04) 从初始化阶段,定时器任务或者中断复位程序里面调用了除
    • TX_NO_WAIT 以外的等待选项。
    • TX_PTR_ERROR:(0x03) 无效的内存单元存放地址。

注意事项:

  •   可以在初始化,任务,定时器组或中断复位程序里面调用。

使用举例:

TX_BLOCK_POOL AppBlock;
uint8_t  *BlockPtr;

/* 申请内存块,每次申请4字节 */
status = tx_block_allocate(&AppBlock, 
             (VOID **)&BlockPtr,
            X_NO_WAIT);
if(status == TX_SUCCESS)
{
    printf("AppBlock内存块申请成功\\r\\n");
}

22.5 内存块释放函数tx_block_release

函数原型:

UINT tx_block_release(VOID *block_ptr);

函数描述:

用于释放从内存块中申请的内存单元。

函数参数:

  •   第1个参数是内存控制块。
    •   返回值
    • TX_SUCCESS:(0x00) 成功释放内存块。
    • TX_PTR_ERROR:(0x03) 无效的内存单元存放地址。

注意事项:

  •   可以在初始化,任务,定时器组或中断复位程序里面调用。

使用举例:

uint8_t  *BlockPtr;

status = tx_block_release(BlockPtr);
if(status == TX_SUCCESS)
{
    printf("AppBlock内存块释放成功\\r\\n");
}

22.6 内存池创建函数tx_byte_pool_create

函数原型:

UINT tx_byte_pool_create(
    TX_BYTE_POOL *pool_ptr,
    CHAR *name_ptr, 
    VOID *pool_start,
    ULONG pool_size);

函数描述:

此函数用于内存池创建。

函数参数:

  •   第1个参数是内存池控制块。
  •   第2个参数是内存池名字。
  •   第3个参数是内存池首地址,必须ULONG对齐,即4字节对齐。
  •   第4个参数是内存池大小,单位字节。
  •   返回值
    • TX_SUCCESS:(0X00) 成功创建内存池。
    • TX_POOL_ERROR:(0x02) 内存池指针无效。指针为 NULL 或池已创建。
    • TX_PTR_ERROR:(0x03) 内存池的起始地址无效。
    • TX_SIZE_ERROR:(0x05) 内存池大小无效。
    • NX_CALLER_ERROR:(0x13) 无效调用。

注意事项:

  可以在初始化和任务中调用。

使用举例:

TX_BYTE_POOL AppPool;

uint32_t AppPoolBuf[1024];

/* 创建内存池,类似malloc和free */    
tx_byte_pool_create(&AppPool, 
        "AppPool",
         (VOID *)AppPoolBuf,     /* 内存池地址,需要保证4字节对齐 */
        sizeof(AppBlockBuf));    /* 内存池大小 */

22.7 内存池申请函数tx_byte_allocate

函数原型:

UINT tx_byte_allocate(
    TX_BYTE_POOL *pool_ptr,
    VOID **memory_ptr, 
    ULONG memory_size,
    ULONG wait_option);

函数描述:

用于从内存池中申请指定字节数。

函数参数:

  •   第1个参数是内存池控制块。
  •   第2个参数用于存放申请的内存地址。
  •   第3个参数是申请的字节数。
  •   第4个参数是没有可用的内存时执行方式,支持如下三种参数
    •   TX_NO_WAIT (0x00000000),表示不管是否获取成功,立即返回。如果在初始化阶段调用,必须要设置成这个参数。
    •   TX_WAIT_FOREVER (0xFFFFFFFF),表示永久等待,直到有内存单元可用。
    •   等待时间,范围0x00000001 到 0xFFFFFFFE,单位系统时钟节拍、
  •   返回值
    • TX_SUCCESS:(0x00) 成功分配内存块。
    • TX_DELETED:(0x01) 线程挂起时删除了内存块。
    • TX_NO_MEMORY:(0X10) 服务无法在指定的等待时间内分配内存块。
    • TX_WAIT_ABORTED:(0x1A) 挂起状态由其他线程、计时器或 ISR 中止。
    • TX_POOL_ERROR:(0x02) 内存块指针无效。
    • TX_WAIT_ERROR:(0x04) 从初始化阶段,定时器任务或者中断复位程序里面调用了除
    • TX_NO_WAIT 以外的等待选项。
    • TX_PTR_ERROR:(0x03) 无效的内存单元存放地址。
    • TX_SIZE_ERROR:(0X05) 所请求的大小为零或超过池大小。
    • TX_CALLER_ERROR:(0x13) 无效的调用。

注意事项:

  •   可以在初始化和任务里面调用。
  •   不可用于时间关键的场景,因为申请的时间不是确定

使用举例:

TX_BYTE_POOL AppPool;
uint8_t  *PoolPtr;
ULONG available;        

status = tx_byte_allocate(&AppPool,
             (VOID **)&PoolPtr,
            77, 
            TX_NO_WAIT);
if(status == TX_SUCCESS)
{
    printf("AppPool内存池申请成功\\r\\n");
    
    tx_byte_pool_info_get(&AppPool, 
            TX_NULL,
            &available, 
            TX_NULL,
            TX_NULL, 
            TX_NULL,
            TX_NULL);
    
    printf("内存池剩余大小 = %d字节\\r\\n", (int)available);
}

22.8 内存池释放函数tx_byte_release

函数原型:

UINT tx_byte_release(VOID *memory_ptr);

函数描述:

用于内存释放。

函数参数:

  •   第1个参数是内存控制块。
  •   返回值
    • TX_SUCCESS:(0x00) 成功释放内存块。
    • TX_PTR_ERROR:(0x03) 内存区域指针无效。
    • TX_CALLER_ERROR:(0x13) 无效的调用。

注意事项:

  可以在初始化和任务里面调用。

使用举例:

TX_BYTE_POOL AppPool;
uint8_t  *PoolPtr;
ULONG available;

status = tx_byte_release(PoolPtr);
if(status == TX_SUCCESS)
{
    printf("AppPool内存池释放成功\\r\\n");
        
    tx_byte_pool_info_get(&AppPool, 
            TX_NULL,
            &available, 
                TX_NULL,
                TX_NULL, 
            TX_NULL,
                TX_NULL);
    
    printf("内存池剩余大小 = %d字节\\r\\n", (int)available);
}

22.9 内存池使用情况获取函数tx_byte_pool_info_get

函数原型:

UINT tx_byte_pool_info_get(
    TX_BYTE_POOL *pool_ptr, 
    CHAR **name,
    ULONG *available, 
    ULONG *fragments,
    TX_THREAD **first_suspended,
    ULONG *suspended_count,
    TX_BYTE_POOL **next_pool);

函数描述:

用于获取内存池的使用情况。

函数参数:

  •   第1个参数是内存池控制块。
  •   第2个参数是内存池名字地址。
  •   第3个参数是剩余字节数。
  •   第4个参数是内存池中内存片段总数。
  •   第5个参数是内存挂起列表中第1个等待的任务。
  •   第6个参数是内存池中当前挂起的任务数。
  •   第7个参数是下个内存池地址。
  •   返回值
    • TX_SUCCESS:(0x00) 信息获取成功。
    • TX_POOL_ERROR:(0x03) 无效的内存池控制块地址。

注意事项:

  •   可以在初始化,任务,定时器组或中断复位程序里面调用。
  •   如果函数的形参设置为TX_NULL,表示用不到。

使用举例:

TX_BYTE_POOL AppPool;
uint8_t  *PoolPtr;
ULONG available;

status = tx_byte_release(PoolPtr);
if(status == TX_SUCCESS)
{
    printf("AppPool内存池释放成功\\r\\n");
        
    tx_byte_pool_info_get(&AppPool, 
            TX_NULL,
            &available, 
                TX_NULL,
                TX_NULL, 
            TX_NULL,
                TX_NULL);
    
    printf("内存池剩余大小 = %d字节\\r\\n", (int)available);
}

22.10          实验例程

配套例子:

V7-3017_ThreadX Malloc

实验目的:

  1. 学习ThreadX动态内存管理

实验内容:

1、共创建了如下几个任务,通过按下按键K1可以通过串口或者RTT打印任务堆栈使用情况                                   

========================================================

         CPU利用率 =  0.89%

         任务执行时间 = 0.586484645s

         空闲执行时间 = 85.504470575s

         中断执行时间 = 0.173225395s

         系统总执行时间 = 86.264180615s              

=======================================================

        任务优先级 任务栈大小 当前使用栈  最大栈使用   任务名

          Prio     StackSize   CurStack    MaxStack   Taskname

          2         4092        303         459      App Task Start

          5         4092        167         167      App Msp Pro

          4         4092        167         167      App Task UserIF

           5         4092        167         167      App Task COM

           0         1020        191         191      System Timer Thread           

串口软件可以使用SecureCRT或者H7-TOOL RTT查看打印信息。

App Task Start任务  :启动任务,这里用作BSP驱动包处理。

App Task MspPro任务 :消息处理。

App Task UserIF任务 :按键消息处理。

App Task COM任务   :这里用作LED闪烁。

System Timer Thread任务:系统定时器任务

2、K2按键按下演示内存块的申请和释放,K3按键按下演示内存池的申请和释放。

3、(1) 凡是用到printf函数的全部通过函数App_Printf实现。

    (2) App_Printf函数做了信号量的互斥操作,解决资源共享问题。

4、默认上电是通过串口打印信息,如果使用RTT打印信息

(1)   MDK AC5,MDK AC6或IAR通过使能bsp.h文件中的宏定义为1即可

#define Enable_RTTViewer  1

(2)   Embedded Studio继续使用此宏定义为0, 因为Embedded Studio仅制作了调试状态RTT方式查看。

串口打印信息方式(AC5,AC6和IAR):

波特率 115200,数据位 8,奇偶校验位无,停止位 1

 

RTT打印信息方式(AC5,AC6和IAR):

Embedded Studio仅支持调试状态RTT打印:

由于Embedded Studio不支持中文,所以中文部分显示乱码,不用管。

程序执行框图:

22.11          总结

本章节主要为大家讲解了ThreadX内存管理的实现方法,关于嵌入式内存管理的方案还有很多,有兴趣的同学可以查阅相关资料了解一下。

以上是关于STM32F429第3章 ThreadX USBX协议栈移植到STM32F429的主要内容,如果未能解决你的问题,请参考以下文章

STM32F429第22章 ThreadX动态内存管理

STM32F429第18章 ThreadX消息队列

STM32F429第20章 ThreadX互斥信号量

STM32F429第19章 ThreadX信号量

STM32F429第21章 ThreadX定时器组

STM32F429第17章 ThreadX事件标志组