13、MDK分散加载方式管理多块内存

news2024/10/5 17:21:20

MDK分散加载:

默认情况下是通过MDK的option选项设置Flash和RAM大小,这种情况下所有的管理工作都是编译来处理的,
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

MDK自动生成的分散加载文件:H7_ProjectTest.sct

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00020000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00020000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
  RW_IRAM2 0x24000000 0x00080000  {
   .ANY (+RW +ZI)
  }
}

看着这文件前需要先看下各RAM的地址和大小,工程使用的STM32H750VBT6
在这里插入图片描述
未全部写出,只写出了主要使用的部分
重新编写的MDK分散加载文件,后面示例使用的也是这个文件:stm32h750vb_user.sct

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; SRAM分散加载文件
; *************************************************************

LR_IROM1 0x08000000 0x00200000 { ; load region size_region;加载域
ER_IROM1 0x08000000 0x00200000 { ; load address = execution address;执行域对应H7的Flash地址和大小
*.o (RESET, +First);将启动文件 startup_stm32h743xx.s 有个段名为 RESET 的代码段(主要存储了中断向量表),将其存放在Flash
*(InRoot$$Sections);将将 MDK 的一些库文件全部放在根域,比如__main.o, _scatter*.o, _dc*.o
.ANY (+RO);将目标文件中所有具有 RO 只读属性的数据放在这里,即 ER_IROM1
}
; RW data - 128KB DTCM
RW_IRAM1 0x20000000 0x00020000 {
.ANY (+RW +ZI);将目标文件中所有具有 RW 和 ZI 数据放在这里
}
; RW data - 512KB AXI SRAM
RW_IRAM2 0x24000000 0x00080000 {
*(.RAM_D1);给这个域专门配了一个名字 .RAM_D1,这样就可以通过__attribute__((section("name")))将其分配到这个RAM域
}
; RW data - 128KB SRAM1(0x30000000) + 128KB SRAM2(0x3002 0000) + 32KB SRAM3(0x30040000)
RW_IRAM3 0x30000000 0x00048000 {
*(.RAM_D2)
}
; RW data - 64KB SRAM4(0x38000000)
RW_IRAM4 0x38000000 0x00010000 {
*(.RAM_D3)
}
}

注意:
在这里插入图片描述

__HAL_RCC_D2SRAM1_CLK_ENABLE();
__HAL_RCC_D2SRAM2_CLK_ENABLE();
__HAL_RCC_D2SRAM2_CLK_ENABLE();

使用分散加载文件:
在定义变量时:

__attribute__((section(".RAM_D1"))) uint32_t AXISRAMBuf[10] = {0,0,0,0,0,0,0,0,0,0};//建议程序初始化后重新对变量进行初始化,否则该值有可能不确定

分散加载示例

在这里插入图片描述
在这里插入图片描述
main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* 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 PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MPU_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

__attribute__((section(".RAM_D1"))) uint32_t AXISRAMBuf[10] = {0,0,0,0,0,0,0,0,0,0};
__attribute__((section(".RAM_D1"))) uint16_t AXISRAMCount = 0;

__attribute__((section(".RAM_D2"))) uint32_t D2SRAMBuf[10] = {0,0,0,0,0,0,0,0,0,0};
__attribute__((section(".RAM_D2"))) uint16_t D2SRAMCount = 0;

__attribute__((section(".RAM_D3"))) uint32_t D3SRAMBuf[10] = {0,0,0,0,0,0,0,0,0,0};
__attribute__((section(".RAM_D3"))) uint16_t D3SRAMCount = 0;

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MPU Configuration--------------------------------------------------------*/
  MPU_Config();

  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();

  /* Enable D-Cache---------------------------------------------------------*/
  SCB_EnableDCache();

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */
__HAL_RCC_D2SRAM1_CLK_ENABLE();
__HAL_RCC_D2SRAM2_CLK_ENABLE();
__HAL_RCC_D2SRAM2_CLK_ENABLE();

for(uint8_t i = 0;i < 10;i++)
{
  AXISRAMBuf[i] = 0;
  D2SRAMBuf[i] = 0;
  D3SRAMBuf[i] = 0;
}

AXISRAMCount = 0;
D2SRAMCount = 0;
D3SRAMCount = 0;
  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    printf("system\n");HAL_Delay(2000);
    AXISRAMBuf[0]++;AXISRAMBuf[5]++;AXISRAMBuf[9]++;
    D2SRAMBuf[0]++;D2SRAMBuf[5]++;D2SRAMBuf[9]++;
    D3SRAMBuf[0]++;D3SRAMBuf[5]++;D3SRAMBuf[9]++;
    AXISRAMCount += 5;
    D2SRAMCount += 2;
    D3SRAMCount += 1;

    printf("AXISRAMBuf[0]=%d AXISRAMBuf[5]=%d AXISRAMBuf[9]=%d AXISRAMCount=%d\n",\
            AXISRAMBuf[0],AXISRAMBuf[5],AXISRAMBuf[9],AXISRAMCount);HAL_Delay(100);
    printf("D2SRAMBuf[0]=%d D2SRAMBuf[5]=%d D2SRAMBuf[9]=%d D2SRAMCount=%d\n",\
            D2SRAMBuf[0],D2SRAMBuf[5],D2SRAMBuf[9],D2SRAMCount);HAL_Delay(100);
    printf("D3SRAMBuf[0]=%d D3SRAMBuf[5]=%d D3SRAMBuf[9]=%d D3SRAMCount=%d\n",\
            D3SRAMBuf[0],D3SRAMBuf[5],D3SRAMBuf[9],D3SRAMCount);HAL_Delay(100);
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 60;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/* MPU Configuration */

void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};

  /* Disables the MPU */
  HAL_MPU_Disable();
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0x24000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER1;
  MPU_InitStruct.BaseAddress = 0x60000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_256MB;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER2;
  MPU_InitStruct.BaseAddress = 0x30000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_128KB;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER3;
  MPU_InitStruct.BaseAddress = 0x30020000;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER4;
  MPU_InitStruct.BaseAddress = 0x30040000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_32KB;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER5;
  MPU_InitStruct.BaseAddress = 0x38000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /* Enables the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  printf("Error_Handler\n");
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

在这里插入图片描述
注意,一定要在使用前进行单独初始化,否则会出现不定的初始值:

  /* USER CODE BEGIN Init */
__HAL_RCC_D2SRAM1_CLK_ENABLE();
__HAL_RCC_D2SRAM2_CLK_ENABLE();
__HAL_RCC_D2SRAM2_CLK_ENABLE();

// for(uint8_t i = 0;i < 10;i++)//使用前不对其重新初始化
// {
//   AXISRAMBuf[i] = 0;
//   D2SRAMBuf[i] = 0;
//   D3SRAMBuf[i] = 0;
// }

AXISRAMCount = 0;
D2SRAMCount = 0;
D3SRAMCount = 0;
  /* USER CODE END Init */

在这里插入图片描述
示例中的MPU配置为:
在这里插入图片描述
void MPU_Config(void)

void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};

  /* Disables the MPU */
  HAL_MPU_Disable();
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0x24000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER1;
  MPU_InitStruct.BaseAddress = 0x60000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_256MB;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER2;
  MPU_InitStruct.BaseAddress = 0x30000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_128KB;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER3;
  MPU_InitStruct.BaseAddress = 0x30020000;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER4;
  MPU_InitStruct.BaseAddress = 0x30040000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_32KB;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER5;
  MPU_InitStruct.BaseAddress = 0x38000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /* Enables the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}

开启Cache指令

  /* MPU Configuration--------------------------------------------------------*/
  MPU_Config();

  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();

  /* Enable D-Cache---------------------------------------------------------*/
  SCB_EnableDCache();

对TCM,SRAM进行内存动态分配实现

此处直接引用的安富莱例程:
在这里插入图片描述
rtx_lib.h

/*
*********************************************************************************************************
*
*	模块名称 : 动态内存管理
*	文件名称 : rtx_memory.h
*	版    本 : V1.0
*	说    明 : 将RTX5的动态内存管理整理出来, 可以管理多个内存块
*
*	修改记录 :
*		版本号   日期         作者        说明
*		V1.0    2018-04-09   Eric2013   将RTX5的动态内存管理整理出来
*
*	Copyright (C), 2018-2030, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*/	
/*
 * Copyright (c) 2013-2018 Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the License); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * -----------------------------------------------------------------------------
 *
 * Project:     CMSIS-RTOS RTX
 * Title:       RTX Library definitions
 *
 * -----------------------------------------------------------------------------
 */

#ifndef RTX_LIB_H_
#define RTX_LIB_H_

#include <string.h>
#include <stdint.h>
#include "stm32h7xx.h"


//  Memory Pool Header structure
typedef struct {
  uint32_t size;                // Memory Pool size
  uint32_t used;                // Used Memory
} mem_head_t;

//  Memory Block Header structure
typedef struct mem_block_s {
  struct mem_block_s *next;     // Next Memory Block in list
  uint32_t            info;     // Block Info or max used Memory (in last block)
} mem_block_t;

//  Memory Block Info: Length = <31:2>:'00', Type = <1:0>
#define MB_INFO_LEN_MASK        0xFFFFFFFCU     // Length mask
#define MB_INFO_TYPE_MASK       0x00000003U     // Type mask

//  Memory Head Pointer
__STATIC_INLINE mem_head_t *MemHeadPtr (void *mem) {
  //lint -e{9079} -e{9087} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
  return ((mem_head_t *)mem);
}

//  Memory Block Pointer
__STATIC_INLINE mem_block_t *MemBlockPtr (void *mem, uint32_t offset) {
  uint32_t     addr;
  mem_block_t *ptr;

  //lint --e{923} --e{9078} "cast between pointer and unsigned int" [MISRA Note 8]
  addr = (uint32_t)mem + offset;
  ptr  = (mem_block_t *)addr;

  return ptr;
}

//  ==== Library functions ====

// Memory Heap Library functions
extern uint32_t osRtxMemoryInit (void *mem, uint32_t size);
extern void    *osRtxMemoryAlloc(void *mem, uint32_t size, uint32_t type);
extern uint32_t osRtxMemoryFree (void *mem, void *block);


#endif  // RTX_LIB_H_

rtx_memory.c

/*
*********************************************************************************************************
*
*	模块名称 : 动态内存管理
*	文件名称 : rtx_memory.c
*	版    本 : V1.0
*	说    明 : 将RTX5的动态内存管理整理出来, 可以管理多个内存块
*
*	修改记录 :
*		版本号   日期         作者        说明
*		V1.0    2018-04-09   Eric2013   将RTX5的动态内存管理整理出来
*
*	Copyright (C), 2018-2030, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*/	
/*
 * Copyright (c) 2013-2018 Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the License); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * -----------------------------------------------------------------------------
 *
 * Project:     CMSIS-RTOS RTX
 * Title:       Memory functions
 *
 * -----------------------------------------------------------------------------
 */
 
#include "rtx_lib.h"




//  ==== Library functions ====

/// Initialize Memory Pool with variable block size.
/// \param[in]  mem             pointer to memory pool.
/// \param[in]  size            size of a memory pool in bytes.
/// \return 1 - success, 0 - failure.
__WEAK uint32_t osRtxMemoryInit (void *mem, uint32_t size) {
  mem_head_t  *head;
  mem_block_t *ptr;

  // Check parameters
  //lint -e{923} "cast from pointer to unsigned int" [MISRA Note 7]
  if ((mem == NULL) || (((uint32_t)mem & 7U) != 0U) || ((size & 7U) != 0U) ||
      (size < (sizeof(mem_head_t) + (2U*sizeof(mem_block_t))))) {
    //EvrRtxMemoryInit(mem, size, 0U);
    //lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return 0U;
  }

  // Initialize memory pool header
  head = MemHeadPtr(mem);
  head->size = size;
  head->used = sizeof(mem_head_t) + sizeof(mem_block_t);

  // Initialize first and last block header
  ptr = MemBlockPtr(mem, sizeof(mem_head_t));
  ptr->next = MemBlockPtr(mem, size - sizeof(mem_block_t));
  ptr->next->next = NULL;
  ptr->next->info = sizeof(mem_head_t) + sizeof(mem_block_t);
  ptr->info = 0U;

  //EvrRtxMemoryInit(mem, size, 1U);

  return 1U;
}

/// Allocate a memory block from a Memory Pool.
/// \param[in]  mem             pointer to memory pool.
/// \param[in]  size            size of a memory block in bytes.
/// \param[in]  type            memory block type: 0 - generic, 1 - control block
/// \return allocated memory block or NULL in case of no memory is available.
__WEAK void *osRtxMemoryAlloc (void *mem, uint32_t size, uint32_t type) {
  mem_block_t *ptr;
  mem_block_t *p, *p_new;
  uint32_t     block_size;
  uint32_t     hole_size;

  // Check parameters
  if ((mem == NULL) || (size == 0U) || ((type & ~MB_INFO_TYPE_MASK) != 0U)) {
    //EvrRtxMemoryAlloc(mem, size, type, NULL);
    //lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return NULL;
  }

  // Add block header to size
  block_size = size + sizeof(mem_block_t);
  // Make sure that block is 8-byte aligned
  block_size = (block_size + 7U) & ~((uint32_t)7U);

  // Search for hole big enough
  p = MemBlockPtr(mem, sizeof(mem_head_t));
  for (;;) {
    //lint -e{923} -e{9078} "cast from pointer to unsigned int"
    hole_size  = (uint32_t)p->next - (uint32_t)p;
    hole_size -= p->info & MB_INFO_LEN_MASK;
    if (hole_size >= block_size) {
      // Hole found
      break;
    }
    p = p->next;
    if (p->next == NULL) {
      // Failed (end of list)
      //EvrRtxMemoryAlloc(mem, size, type, NULL);
      //lint -e{904} "Return statement before end of function" [MISRA Note 1]
      return NULL;
    }
  }

  // Update used memory
  (MemHeadPtr(mem))->used += block_size;

  // Update max used memory
  p_new = MemBlockPtr(mem, (MemHeadPtr(mem))->size - sizeof(mem_block_t));
  if (p_new->info < (MemHeadPtr(mem))->used) {
    p_new->info = (MemHeadPtr(mem))->used;
  }

  // Allocate block
  if (p->info == 0U) {
    // No block allocated, set info of first element
    p->info = block_size | type;
    ptr = MemBlockPtr(p, sizeof(mem_block_t));
  } else {
    // Insert new element into the list
    p_new = MemBlockPtr(p, p->info & MB_INFO_LEN_MASK);
    p_new->next = p->next;
    p_new->info = block_size | type;
    p->next = p_new;
    ptr = MemBlockPtr(p_new, sizeof(mem_block_t));
  }

  //EvrRtxMemoryAlloc(mem, size, type, ptr);

  return ptr;
}

/// Return an allocated memory block back to a Memory Pool.
/// \param[in]  mem             pointer to memory pool.
/// \param[in]  block           memory block to be returned to the memory pool.
/// \return 1 - success, 0 - failure.
__WEAK uint32_t osRtxMemoryFree (void *mem, void *block) {
  const mem_block_t *ptr;
        mem_block_t *p, *p_prev;

  // Check parameters
  if ((mem == NULL) || (block == NULL)) {
    //EvrRtxMemoryFree(mem, block, 0U);
    //lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return 0U;
  }

  // Memory block header
  ptr = MemBlockPtr(block, 0U);
  ptr--;

  // Search for block header
  p_prev = NULL;
  p = MemBlockPtr(mem, sizeof(mem_head_t));
  while (p != ptr) {
    p_prev = p;
    p = p->next;
    if (p == NULL) {
      // Not found
      //EvrRtxMemoryFree(mem, block, 0U);
      //lint -e{904} "Return statement before end of function" [MISRA Note 1]
      return 0U;
    }
  }

  // Update used memory
  (MemHeadPtr(mem))->used -= p->info & MB_INFO_LEN_MASK;

  // Free block
  if (p_prev == NULL) {
    // Release first block, only set info to 0
    p->info = 0U;
  } else {
    // Discard block from chained list
    p_prev->next = p->next;
  }

  //EvrRtxMemoryFree(mem, block, 1U);

  return 1U;
}

main.c

/*
*********************************************************************************************************
*
*	模块名称 : 主程序模块
*	文件名称 : main.c
*	版    本 : V1.0
*	说    明 : TCM,SRAM等五块内存的动态内存分配实现。
*              实验目的:
*                1. 学习TCM,SRAM等五块内存的动态内存分配实现。
*              实验内容:
*                1. 启动自动重装软件定时器0,每100ms翻转一次LED2。
*              实验操作:
*                1. K1键按下,从DTCM依次申请280字节,64字节和6111字节。
*                2. K1键松开,释放从DTCM申请的空间。
*                3. K2键按下,从AXI SRAM依次申请160字节,32字节和2333字节。
*                4. K2键松开,释放从AXI SRAM申请的空间。
*                5. K3键按下,从D2域SRAM依次申请200字节,96字节和4111字节。
*                6. K3键松开,释放从D2域SRAM申请的空间。
*                7. 摇杆OK键按下,从D3域SRAM依次申请300字节,128字节和5111字节。
*                8. 摇杆OK键松开,释放从D3域SRAM申请的空间。
*              注意事项:
*                1. 本实验推荐使用串口软件SecureCRT查看打印信息,波特率115200,数据位8,奇偶校验位无,停止位1。
*                2. 务必将编辑器的缩进参数和TAB设置为4来阅读本文件,要不代码显示不整齐。
*
*	修改记录 :
*		版本号   日期         作者        说明
*		V1.0    2018-12-12   Eric2013     1. CMSIS软包版本 V5.4.0
*                                         2. HAL库版本 V1.3.0
*
*	Copyright (C), 2018-2030, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*/	
#include "bsp.h"			/* 底层硬件驱动 */



/* 定义例程名和例程发布日期 */
#define EXAMPLE_NAME	"V7-TCM,SRAM等五块内存的动态内存分配实现"
#define EXAMPLE_DATE	"2018-12-12"
#define DEMO_VER		"1.0"

static void PrintfLogo(void);
static void PrintfHelp(void);


/* DTCM, 64KB */
mem_head_t *DTCMUsed;
uint64_t AppMallocDTCM[64*1024/8];


#if defined ( __ICCARM__ )    /* 使用的IAR */

/* D1域, AXI SRAM, 512KB */
mem_head_t *AXISRAMUsed;
#pragma location = 0x24000000
uint64_t AppMallocAXISRAM[512*1024/8];

/* D2域, 128KB SRAM1(0x30000000) + 128KB SRAM2(0x30020000) + 32KB SRAM3(0x30040000)  */
mem_head_t *SRAM1Used; 
#pragma location = 0x30000000
uint64_t AppMallocSRAM1[288*1024/8];

/* D3域, SRAM4, 64KB */
mem_head_t *SRAM4Used;
#pragma location = 0x38000000
uint64_t AppMallocSRAM4[64*1024/8];

#elif defined ( __CC_ARM )  /* 使用的MDK */
/* D1域, AXI SRAM, 512KB */
mem_head_t *AXISRAMUsed;
uint64_t AppMallocAXISRAM[512*1024/8]__attribute__((at(0x24000000)));

/* D2域, 128KB SRAM1(0x30000000) + 128KB SRAM2(0x30020000) + 32KB SRAM3(0x30040000)  */
mem_head_t *SRAM1Used; 
uint64_t AppMallocSRAM1[288*1024/8]__attribute__((at(0x30000000)));

/* D3域, SRAM4, 64KB */
mem_head_t *SRAM4Used;
uint64_t AppMallocSRAM4[64*1024/8]__attribute__((at(0x38000000)));
#endif

/*
*********************************************************************************************************
*	函 数 名: main
*	功能说明: c程序入口
*	形    参: 无
*	返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{
	uint8_t ucKeyCode;		/* 按键代码 */
	uint32_t *DTCM_Addres0, *AXISRAM_Addres0, *SRAM1_Addres0, *SRAM4_Addres0;
	uint16_t *DTCM_Addres1, *AXISRAM_Addres1, *SRAM1_Addres1, *SRAM4_Addres1;
	uint8_t  *DTCM_Addres2, *AXISRAM_Addres2, *SRAM1_Addres2, *SRAM4_Addres2;
    
    
	bsp_Init();		/* 硬件初始化 */
	
	/* 初始化动态内存空间 */
	osRtxMemoryInit(AppMallocDTCM,    sizeof(AppMallocDTCM));
	osRtxMemoryInit(AppMallocAXISRAM, sizeof(AppMallocAXISRAM));
	osRtxMemoryInit(AppMallocSRAM1,   sizeof(AppMallocSRAM1));
	osRtxMemoryInit(AppMallocSRAM4,   sizeof(AppMallocSRAM4));
	
	PrintfLogo();	/* 打印例程名称和版本等信息 */
	PrintfHelp();	/* 打印操作提示 */

	bsp_StartAutoTimer(0, 100);	/* 启动1个100ms的自动重装的定时器 */
	

	/* 进入主程序循环体 */
	while (1)
	{
		bsp_Idle();		/* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */

		/* 判断定时器超时时间 */
		if (bsp_CheckTimer(0))	
		{
			/* 每隔100ms 进来一次 */  
			bsp_LedToggle(2);
		}

		/* 按键滤波和检测由后台systick中断服务程序实现,我们只需要调用bsp_GetKey读取键值即可。 */
		ucKeyCode = bsp_GetKey();	/* 读取键值, 无键按下时返回 KEY_NONE = 0 */
		if (ucKeyCode != KEY_NONE)
		{
			switch (ucKeyCode)
			{
                /* 从DTCM依次申请280字节,64字节和6111字节 */
				case KEY_DOWN_K1:	
                    /* 从DTCM申请280字节空间,使用指针变量DTCM_Addres0操作这些空间时不要超过280字节大小 */	
					printf("=========================================================\r\n");
					DTCM_Addres0 = osRtxMemoryAlloc(AppMallocDTCM, 280, 0);
					DTCMUsed = MemHeadPtr(AppMallocDTCM);
					printf("DTCM总大小 = %d字节,申请大小 = 0280字节,当前共使用大小 = %d字节\r\n", 
				                                                DTCMUsed->size, DTCMUsed->used);
				
					/* 从DTCM申请64字节空间,使用指针变量DTCM_Addres1操作这些空间时不要超过64字节大小 */	
					DTCM_Addres1 = osRtxMemoryAlloc(AppMallocDTCM, 64, 0);
					DTCMUsed = MemHeadPtr(AppMallocDTCM);
					printf("DTCM总大小 = %d字节,申请大小 = 0064字节,当前共使用大小 = %d字节\r\n", 
											                   DTCMUsed->size, DTCMUsed->used);
				
					/* 从DTCM申请6111字节空间,使用指针变量DTCM_Addres2操作这些空间时不要超过6111字节大小 */	
					DTCM_Addres2 = osRtxMemoryAlloc(AppMallocDTCM, 6111, 0);
					DTCMUsed = MemHeadPtr(AppMallocDTCM);
					printf("DTCM总大小 = %d字节,申请大小 = 6111字节,当前共使用大小 = %d字节\r\n", 
				                                                DTCMUsed->size, DTCMUsed->used);
					break;
				
				/* 释放从DTCM申请的空间 */
				case KEY_UP_K1:	
					/* 释放从DTCM申请的280字节空间 */
					osRtxMemoryFree(AppMallocDTCM, DTCM_Addres0);
					DTCMUsed = MemHeadPtr(AppMallocDTCM);
					printf("释放DTCM动态内存区申请的0280字节,当前共使用大小 = %d字节\r\n", DTCMUsed->used);
				
					/* 释放从DTCM申请的64字节空间 */
					osRtxMemoryFree(AppMallocDTCM, DTCM_Addres1);
					DTCMUsed = MemHeadPtr(AppMallocDTCM);
					printf("释放DTCM动态内存区申请的0064字节,当前共使用大小 = %d字节\r\n", DTCMUsed->used);
				
					/* 释放从DTCM申请的6111字节空间 */
					osRtxMemoryFree(AppMallocDTCM, DTCM_Addres2);
					DTCMUsed = MemHeadPtr(AppMallocDTCM);
					printf("释放DTCM动态内存区申请的6111字节,当前共使用大小 = %d字节\r\n", DTCMUsed->used);
					break;
				
				/* 从AXI SRAM依次申请160字节,32字节和2333字节 */
				case KEY_DOWN_K2:	
                    /* 从AXI SRAM 申请160字节空间,使用指针变量AXISRAM_Addres0操作这些空间时不要超过160字节大小 */	
					printf("=========================================================\r\n");				
					AXISRAM_Addres0 = osRtxMemoryAlloc(AppMallocAXISRAM, 160, 0);
					AXISRAMUsed = MemHeadPtr(AppMallocAXISRAM);
					printf("AXI SRAM总大小 = %d字节,申请大小 = 0162字节,当前共使用大小 = %d字节\r\n", 
				                                                AXISRAMUsed->size, AXISRAMUsed->used);
				
					/* 从AXI SRAM 申请32字节空间,使用指针变量AXISRAM_Addres1操作这些空间时不要超过32字节大小 */	
					AXISRAM_Addres1 = osRtxMemoryAlloc(AppMallocAXISRAM, 32, 0);
					AXISRAMUsed = MemHeadPtr(AppMallocAXISRAM);
					printf("AXI SRAM总大小 = %d字节,申请大小 = 0032字节,当前共使用大小 = %d字节\r\n", 
											                   AXISRAMUsed->size, AXISRAMUsed->used);
				
					/* 从AXI SRAM 申请2333字节空间,使用指针变量AXISRAM_Addres2操作这些空间时不要超过2333字节大小 */	
					AXISRAM_Addres2 = osRtxMemoryAlloc(AppMallocAXISRAM, 2333, 0);
					AXISRAMUsed = MemHeadPtr(AppMallocAXISRAM);
					printf("AXI SRAM总大小 = %d字节,申请大小 = 2333字节,当前共使用大小 = %d字节\r\n", 
				                                                AXISRAMUsed->size, AXISRAMUsed->used);
					break;
				
				/* 释放从AXI SRAM申请的空间 */
				case KEY_UP_K2:	
					/* 释放从AXI SRAM申请的160字节空间 */
					osRtxMemoryFree(AppMallocAXISRAM, AXISRAM_Addres0);
					AXISRAMUsed = MemHeadPtr(AppMallocAXISRAM);
					printf("释放AXI SRAM动态内存区申请的0160字节,当前共使用大小 = %d字节\r\n", AXISRAMUsed->used);
				
					/* 释放从AXI SRAM申请的32字节空间 */
					osRtxMemoryFree(AppMallocAXISRAM, AXISRAM_Addres1);
					AXISRAMUsed = MemHeadPtr(AppMallocAXISRAM);
					printf("释放AXI SRAM动态内存区申请的0032字节,当前共使用大小 = %d字节\r\n", AXISRAMUsed->used);
				
					/* 释放从AXI SRAM申请的2333字节空间 */
					osRtxMemoryFree(AppMallocAXISRAM, AXISRAM_Addres2);
					AXISRAMUsed = MemHeadPtr(AppMallocAXISRAM);
					printf("释放AXI SRAM动态内存区申请的2333字节,当前共使用大小 = %d字节\r\n", AXISRAMUsed->used);
					break;
				
				/* 从D2域SRAM依次申请200字节,96字节和4111字节 */
				case KEY_DOWN_K3:	
                    /* 从D2域的SRAM申请200字节空间,使用指针变量SRAM1_Addres0操作这些空间时不要超过200字节大小 */	
					printf("=========================================================\r\n");				
					SRAM1_Addres0 = osRtxMemoryAlloc(AppMallocSRAM1, 200, 0);
					SRAM1Used = MemHeadPtr(AppMallocSRAM1);
					printf("D2域SRAM总大小 = %d字节,申请大小 = 0200字节,当前共使用大小 = %d字节\r\n", 
				                                                SRAM1Used->size, SRAM1Used->used);
				
					/* 从D2域的SRAM申请96字节空间,使用指针变量SRAM1_Addres1操作这些空间时不要超过96字节大小 */	
					SRAM1_Addres1 = osRtxMemoryAlloc(AppMallocSRAM1, 96, 0);
					SRAM1Used = MemHeadPtr(AppMallocSRAM1);
					printf("D2域SRAM总大小 = %d字节,申请大小 = 0096字节,当前共使用大小 = %d字节\r\n", 
											                   SRAM1Used->size, SRAM1Used->used);
				
					/* 从D2域的SRAM申请4111字节空间,使用指针变量SRAM1_Addres2操作这些空间时不要超过4111字节大小 */	
					SRAM1_Addres2 = osRtxMemoryAlloc(AppMallocSRAM1, 4111, 0);
					SRAM1Used = MemHeadPtr(AppMallocSRAM1);
					printf("D2域SRAM总大小 = %d字节,申请大小 = 4111字节,当前共使用大小 = %d字节\r\n", 
				                                                SRAM1Used->size, SRAM1Used->used);
					break;
				
				/* 释放从D2域SRAM申请的空间 */
				case KEY_UP_K3:	
					/* 释放从D2域的SRAM申请的200字节空间 */
					osRtxMemoryFree(AppMallocSRAM1, SRAM1_Addres0);
					SRAM1Used = MemHeadPtr(AppMallocSRAM1);
					printf("释放D2域SRAM动态内存区申请的0200字节,当前共使用大小 = %d字节\r\n", SRAM1Used->used);
				
					/* 释放从D2域的SRAM申请的96字节空间 */
					osRtxMemoryFree(AppMallocSRAM1, SRAM1_Addres1);
					SRAM1Used = MemHeadPtr(AppMallocSRAM1);
					printf("释放D2域SRAM动态内存区申请的0096字节,当前共使用大小 = %d字节\r\n", SRAM1Used->used);
				
					/* 释放从D2域的SRAM申请的4111字节空间 */
					osRtxMemoryFree(AppMallocSRAM1, SRAM1_Addres2);
					SRAM1Used = MemHeadPtr(AppMallocSRAM1);
					printf("释放D2域SRAM动态内存区申请的4111字节,当前共使用大小 = %d字节\r\n", SRAM1Used->used);
					break;
				
				/* 从D3域SRAM依次申请300字节,128字节和5111字节 */
				case JOY_DOWN_OK:	
                    /* 从D3域的SRAM申请300字节空间,使用指针变量SRAM4_Addres0操作这些空间时不要超过300字节大小 */	
					printf("=========================================================\r\n");				
					SRAM4_Addres0 = osRtxMemoryAlloc(AppMallocSRAM4, 300, 0);
					SRAM4Used = MemHeadPtr(AppMallocSRAM4);
					printf("D3域SRAM总大小 = %d字节,申请大小 = 0300字节,当前共使用大小 = %d字节\r\n", 
				                                                SRAM4Used->size, SRAM4Used->used);
				
					/* 从D3域的SRAM申请96字节空间,使用指针变量SRAM4_Addres1操作这些空间时不要超过96字节大小 */	
					SRAM4_Addres1 = osRtxMemoryAlloc(AppMallocSRAM4, 128, 0);
					SRAM4Used = MemHeadPtr(AppMallocSRAM4);
					printf("D3域SRAM总大小 = %d字节,申请大小 = 0128字节,当前共使用大小 = %d字节\r\n", 
											                   SRAM4Used->size, SRAM4Used->used);
				
					/* 从D3域的SRAM申请5111字节空间,使用指针变量SRAM4_Addres2操作这些空间时不要超过5111字节大小 */	
					SRAM4_Addres2 = osRtxMemoryAlloc(AppMallocSRAM4, 5111, 0);
					SRAM4Used = MemHeadPtr(AppMallocSRAM4);
					printf("D3域SRAM总大小 = %d字节,申请大小 = 5111字节,当前共使用大小 = %d字节\r\n", 
				                                                SRAM4Used->size, SRAM4Used->used);
					break;
				
				/* 释放从D3域SRAM申请的空间 */
				case JOY_UP_OK:	
					/* 释放从D3域的SRAM申请的300字节空间 */
					osRtxMemoryFree(AppMallocSRAM4, SRAM4_Addres0);
					SRAM4Used = MemHeadPtr(AppMallocSRAM4);
					printf("释放D3域SRAM动态内存区申请的0300字节,当前共使用大小 = %d字节\r\n", SRAM4Used->used);
				
					/* 释放从D3域的SRAM申请的128字节空间 */
					osRtxMemoryFree(AppMallocSRAM4, SRAM4_Addres1);
					SRAM4Used = MemHeadPtr(AppMallocSRAM4);
					printf("释放D3域SRAM动态内存区申请的0128字节,当前共使用大小 = %d字节\r\n", SRAM4Used->used);
				
					/* 释放从D3域的SRAM申请的5111字节空间 */
					osRtxMemoryFree(AppMallocSRAM4, SRAM4_Addres2);
					SRAM4Used = MemHeadPtr(AppMallocSRAM4);
					printf("释放D3域SRAM动态内存区申请的5111字节,当前共使用大小 = %d字节\r\n", SRAM4Used->used);
					break;
			
				default:
				  /* 其它的键值不处理 */
				  break;
			}
		}
	}
}

/*
*********************************************************************************************************
*	函 数 名: PrintfHelp
*	功能说明: 打印操作提示
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
static void PrintfHelp(void)
{
	printf("操作提示:\r\n");
	printf("1. K1键按下,从DTCM依次申请280字节,64字节和6111字节\r\n");
	printf("2. K1键松开,释放从DTCM申请的空间\r\n");
	printf("3. K2键按下,从AXI SRAM依次申请160字节,32字节和2333字节\r\n");
	printf("4. K2键松开,释放从AXI SRAM申请的空间\r\n");
	printf("5. K3键按下,从D2域SRAM依次申请200字节,96字节和4111字节\r\n");
	printf("6. K3键松开,释放从D2域SRAM申请的空间\r\n");
	printf("7. 摇杆OK键按下,从D3域SRAM依次申请300字节,128字节和5111字节\r\n");
	printf("8. 摇杆OK键松开,释放从D3域SRAM申请的空间\r\n");
}

/*
*********************************************************************************************************
*	函 数 名: PrintfLogo
*	功能说明: 打印例程名称和例程发布日期, 接上串口线后,打开PC机的超级终端软件可以观察结果
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
static void PrintfLogo(void)
{
	printf("*************************************************************\n\r");
	
	/* 检测CPU ID */
	{
		uint32_t CPU_Sn0, CPU_Sn1, CPU_Sn2;
		
		CPU_Sn0 = *(__IO uint32_t*)(0x1FF1E800);
		CPU_Sn1 = *(__IO uint32_t*)(0x1FF1E800 + 4);
		CPU_Sn2 = *(__IO uint32_t*)(0x1FF1E800 + 8);

		printf("\r\nCPU : STM32H743XIH6, BGA240, 主频: %dMHz\r\n", SystemCoreClock / 1000000);
		printf("UID = %08X %08X %08X\n\r", CPU_Sn2, CPU_Sn1, CPU_Sn0);
	}

	printf("\n\r");
	printf("*************************************************************\n\r");
	printf("* 例程名称   : %s\r\n", EXAMPLE_NAME);	/* 打印例程名称 */
	printf("* 例程版本   : %s\r\n", DEMO_VER);		/* 打印例程版本 */
	printf("* 发布日期   : %s\r\n", EXAMPLE_DATE);	/* 打印例程日期 */

	/* 打印ST的HAL库版本 */
	printf("* HAL库版本  : V1.3.0 (STM32H7xx HAL Driver)\r\n");
	printf("* \r\n");	/* 打印一行空格 */
	printf("* QQ    : 1295744630 \r\n");
	printf("* 旺旺  : armfly\r\n");
	printf("* Email : armfly@qq.com \r\n");
	printf("* 微信公众号: armfly_com \r\n");
	printf("* 淘宝店: armfly.taobao.com\r\n");
	printf("* Copyright www.armfly.com 安富莱电子\r\n");
	printf("*************************************************************\n\r");
}

/***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/

此处建议直接参考安富莱原文

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/464321.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java_异常

Java_异常 1.什么是异常 ​ 生活中的异常&#xff1a;感冒发烧、电脑蓝屏、手机死机等。 ​ 程序中的异常&#xff1a;磁盘空间不足、网络连接中断、被加载的资源不存在等。 ​ 程序异常解决办法&#xff1a;针对程序中非正常情况&#xff0c;Java语言引入了异常&#xff0…

【C++】类和对象(1)

文章目录 前言浅浅了解一、面向过程和面向对象二、 类和对象的关系三、创建类和对象 逐步深入一、类的访问限定符二、 封装三、类的作用域四、类对象模型五、this指针 前言 浅浅了解 一、面向过程和面向对象 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解…

智能汽车开启中央计算革命,全场景智能“车芯”强势崛起

伴随着汽车跨域融合时代的到来&#xff0c;智能汽车芯片正处于快速迭代期&#xff0c;同时牌桌上的玩家也在加速挪换位置。 一方面&#xff0c;包括丰田、大众集团等在内的全球汽车制造商正在进入芯片平台的切换周期&#xff0c;加速推动汽车芯片市场格局的改变。 另一方面&a…

Ubuntu22.04部署eurekaserver集群

Ubuntu22.04部署eurekaserver集群 为了更好的浏览体验&#xff0c;欢迎光顾勤奋的凯尔森同学个人博客http://www.huerpu.cc:7000 每次都启动eureka的项目&#xff0c;太繁琐了&#xff0c;我们把eureka部署到Ubuntu&#xff0c;就可以愉快的玩耍了。 1 配置文件设置 准备了…

设计模式 -- 观察者模式

前言 月是一轮明镜,晶莹剔透,代表着一张白纸(啥也不懂) 央是一片海洋,海乃百川,代表着一块海绵(吸纳万物) 泽是一柄利剑,千锤百炼,代表着千百锤炼(输入输出) 月央泽,学习的一种过程,从白纸->吸收各种知识->不断输入输出变成自己的内容 希望大家一起坚持这个过程,也同…

淘宝天猫数据分析:2023年健康养生三大品类数据分析

随着人们健康意识的不断增强&#xff0c;越来越多的年轻人都开始加入养生大军的队伍中&#xff0c;我国的健康养生产业也迎来了发展机遇。 在天猫平台上&#xff0c;养生茶、养生壶和滋补养生原料是养生市场的几大重点类目&#xff0c;接下来&#xff0c;结合鲸参谋电商数据分析…

Docker 相关概念

1、Docker是什么&#xff1f; 如何确保应用能够在这些环境中运行和通过质量检测&#xff1f;并且在部署过程中不出现令人头疼的版本、配置问题&#xff0c;也无需重新编写代码和进行故障修复&#xff1f; 答案就是使用容器。Docker之所以发展如此迅速&#xff0c;也是因为它对…

电脑硬盘分区合并怎么操作?分享2个方法!

案例&#xff1a;电脑硬盘怎么分区&#xff1f; 【我把我的电脑硬盘分成了多个区域&#xff0c;这样可以方便存储和管理数据。现在我需要调整分区&#xff0c;对分区进行合并&#xff0c;但我不知道该如何操作&#xff0c;有没有小伙伴知道&#xff1f;】 在使用电脑的过程中…

4核8G云服务器4c8g或4h8g指的是什么?

4核8G云服务器什么意思&#xff1f;4c8g或4h8g代表CPU内存配置&#xff0c;4c8g是指4核CPU、8G内存&#xff0c;准确来讲由于是云服务器&#xff0c;4核指的是4核vCPU&#xff0c;4核8G就是指云服务器CPU内存配置。云服务器不只是CPU内存&#xff0c;还有公网带宽和系统盘&…

经典 Learned Index 结构设计及其应用

引言 学习索引是一种新型的索引结构&#xff0c;可以帮助数据库更快地查找数据。学习索引的诞生可以追溯到 2017 年&#xff0c;由 Google Brain 团队的 Kraska 等人在论文[1]中首次提出,探讨了使用神经网络替代传统数据结构&#xff08;如 B-Tree&#xff09;来构建索引的可行…

appuploader 常规使用登录方法

转载&#xff1a;登录appuploader 目录 登录appuploader 常规使用登录方法 双击appuploader.exe 启动appuploader 点击底部的未登录&#xff0c;弹出登录框 在登录框内输入apple开发者账号 如果没有apple开发者账号&#xff0c;只是普通的apple账号&#xff0c;请勾选上未…

题目 2056: 汉诺塔 ==理解递归

题目 2056: 汉诺塔 https://www.dotcpp.com/oj/problem2056.html 做题情况 参考代码&#xff1a; //package Dotcpp;import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt();// prin…

3.30 haas506 2.0开发教程-example - SD卡存储数据读写

SD卡存储数据读写 案例说明数据的写入与读取串口工具读取数据接收数据CSV格式 案例说明 部分设备使用过程中需要保存大量数据到TF卡中&#xff0c;大部分场景拔插TF卡有不太方便。 所以本案例介绍一种使用串口工具取出设备TF卡中的数据保存在电脑中的方法。 保存格式可以自己定…

详细安装使用教程】店侦探 - 跟踪店铺数据,学习运营技巧,引流关键词,电商人必备工具

简介 店侦探插件是一款电商网络浏览插件&#xff0c;能够帮助店主更好地运营自己的网店&#xff0c;这款插件功能十分全面强大&#xff0c;可以全面跟踪店铺的销量情况、引流关键词、直通车、营销活动、宝贝变更跟踪&#xff01;感兴趣的朋友快来体验吧&#xff0c;跟踪店铺数…

常见的用户密码加密及破解方法

用户密码安全是互联网行业需要保障的重要安全之一&#xff0c;由于黑客的入侵和内部的泄露&#xff0c;保证用户密码安全并不是件容易的事情&#xff0c;但如果采用合适的算法加密用户密码&#xff0c;即使信息泄露出去&#xff0c;黑客也无法还原出原始的密码(或者还原的代价非…

vue3 封装ECharts组件

一、前言 前端开发需要经常使用ECharts图表渲染数据信息&#xff0c;在一个项目中我们经常需要使用多个图表&#xff0c;选择封装ECharts组件复用的方式可以减少代码量&#xff0c;增加开发效率。 ECharts图表大家应该用的都比较多&#xff0c;基础的用法就不细说了&#xff…

如何成为企业急需的技术人才:掌握这些技能,提升你的实力和竞争力

在当前竞争激烈的互联网环境中&#xff0c;作为程序员等技术岗&#xff0c;必须不断的学习&#xff0c;才能不断提升自身实力&#xff0c;锻炼自身技能。想要成为一名企业急需的技术人才&#xff0c;需要学习哪些技能呢&#xff1f; 一、IT技术发展背景及历程 IT技术是当今社…

如何借助分布式存储 JuiceFS 加速 AI 模型训练

传统的机器学习模型&#xff0c;数据集比较小&#xff0c;模型的算法也比较简单&#xff0c;使用单机存储&#xff0c;或者本地硬盘就足够了&#xff0c;像 JuiceFS 这样的分布式存储并不是必需品。 随着近几年深度学习的蓬勃发展&#xff0c;越来越多的团队开始遇到了单机存储…

【22-23 春学期】人工智能基础--AI作业6-误差反向传播

老师发布作业链接&#xff1a;(429条消息) 【22-23 春学期】AI作业6-误差反向传播_HBU_David的博客-CSDN博客 目录 老师发布作业链接&#xff1a;(429条消息) 【22-23 春学期】AI作业6-误差反向传播_HBU_David的博客-CSDN博客 1.梯度下降 2.反向传播 3.计算图 4.使用Numpy…

ROS第四十四节——路径规划

1.新建launch文件 nav05_path.launch <launch><node pkg"move_base" type"move_base" respawn"false" name"move_base" output"screen" clear_params"true"><rosparam file"$(find nav_dem…