MDK分散加载:

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


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

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************LR_IROM1 0x08000000 0x00020000  {    ; load region size_regionER_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 sizeuint32_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 listuint32_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 headerhead = MemHeadPtr(mem);head->size = size;head->used = sizeof(mem_head_t) + sizeof(mem_block_t);// Initialize first and last block headerptr = 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 parametersif ((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 sizeblock_size = size + sizeof(mem_block_t);// Make sure that block is 8-byte alignedblock_size = (block_size + 7U) & ~((uint32_t)7U);// Search for hole big enoughp = 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 foundbreak;}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 memoryp_new = MemBlockPtr(mem, (MemHeadPtr(mem))->size - sizeof(mem_block_t));if (p_new->info < (MemHeadPtr(mem))->used) {p_new->info = (MemHeadPtr(mem))->used;}// Allocate blockif (p->info == 0U) {// No block allocated, set info of first elementp->info = block_size | type;ptr = MemBlockPtr(p, sizeof(mem_block_t));} else {// Insert new element into the listp_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 parametersif ((mem == NULL) || (block == NULL)) {//EvrRtxMemoryFree(mem, block, 0U);//lint -e{904} "Return statement before end of function" [MISRA Note 1]return 0U;}// Memory block headerptr = MemBlockPtr(block, 0U);ptr--;// Search for block headerp_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 blockif (p_prev == NULL) {// Release first block, only set info to 0p->info = 0U;} else {// Discard block from chained listp_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) *********************************/

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

13、MDK分散加载方式管理多块内存相关推荐

  1. stm32h7内存分配_stm32h7“分散加载方式管理多块内存”

    默认情况下,我们都是通过 MDK 的 option 选项设置 Flash 和 RAM 大小,如图1 图1 这种情况下,不方便用户将变量定义到指定的 CCM 或者 SDRAM 中.而使用attribut ...

  2. x210开发板的三种启动方式(三星推荐的,分散加载,uboot采用的)

    1.三星推荐的启动方式 (1)将bl1放在在SRAM中运行,将bl2也在SRAM中运行,就像datasheet中描述那样. (2)bootloader必须小于96KB并大于16KB,假定bootloa ...

  3. STM32之MDK分析,分散加载

    STM32分散加载 我们知道MDK的分散加载主要是通过.sct文件实现的,链接器根据.sct文件的配置分配各个节区地址,生成分散加载代码,因此我们通过修改该文件可以定制具体节区的存储位置. 如何打开. ...

  4. 【C语言常识】Keil MDK的分散加载文件.sct

    https://blog.csdn.net/wuhenyouyuyouyu/article/details/71171546?ops_request_misc=%257B%2522request%25 ...

  5. KEIL MDK链接脚本-分散加载文件sct

    在了解keil的链接脚本之前需要了解几个重要概念: RO(ReadOnly):表示程序中的指令和常量 RW(Read/Write):表示程序中已初始化的变量 ZI(Zero):表示程序中未初始化的变量 ...

  6. 从MDK分散加载文件学习STM32启动流程

    一直在用ARM的Cortex-M系列做产品开发,也陆陆续续学习了ARM的启动流程.汇编启动文件,但是总感觉没有连贯的把全部知识串起来,不知道某些汇编语句为什么要这么写,没法按照自己的情况进行修改.今天 ...

  7. sct分散加载文件格式与应用

    *.sct分散加载文件是根据芯片内部FLASH和SRAM存储器概况生成的配置文件,链接器根据该文件的配置分配各个节区地址,生成分散加载代码,通过修改该文件可以定制节区的具体存储位置.例如控制代码的加载 ...

  8. keil的sct文件_STM32 分散加载文件 .sct 解析

    1.STM32 启动文件与 .sct 文件分析 1) 定义STACK段,{NOINIT,读写}:分配一段内存大小为0.5K; 2) 定义HEAP段, {NOINIT,读写}:分配一段内存大小为1K; ...

  9. 从零实现 Cortex-M7从驱动到应用(一)分散加载+SDRAM+SPI_FLASH

    接下来我将与大家分享H750的开发,最终实现emwin的运行. 搭建环境 cubemx 由于cubemx老版本不支持H750,所以只能用新版本,注意:老版本支持工程路径为中文,新版本不支持! 需要H7 ...

最新文章

  1. getaddrinfo()函数详解
  2. Java基础知识——类装载器与反射机制
  3. pg 递归算法_16. 图的________优先搜索遍历算法是一种递归算法,图的________优先搜索遍历算法需要使用队列。...
  4. java 后端校验_如何实现Java后端数据校验?看这篇就足够!
  5. springboot : Failed to decode downloaded font 和 OTS parsing error
  6. 论文浅尝 - ICLR2020 | 用于半监督分类的图形推理学习
  7. python监控windows日志_Python 监控日志的简单示例
  8. 信息学奥赛一本通(2025:【例4.11】体操队)
  9. 信息学奥赛一本通(1032:大象喝水查)
  10. 混淆矩阵(Confusion Matrix)
  11. jq ui 日历控件
  12. 解决在RHEL/CentOS7.4以上版本无法使用AFD(Oracle ASMFD)特性
  13. HMI-66-【MeterDisplay for Arm Linux】液晶仪表Arm Linxu迁移
  14. java gnuplot,用 Gnuplot 绘制实验数据
  15. 飞秋只能发文件不能接收文件的解决办法
  16. Java以毫秒为单位返回秒表记录的流逝时间(即求一个程序段的运行时间)
  17. java对手机芯片有没有要求_芯片对手机到底有多重要
  18. opensips安装教程
  19. selenium +eclipse+firefox/chrome 环境全套搭配
  20. python断网还能用吗_python 断网

热门文章

  1. 挥拍类运动让身体受益颇多,特别是在保护心血管方面
  2. 做自媒体视频实现月入十万难吗?
  3. Jenkins:如何给coding的项目绑定钉钉机器人
  4. 客户自助服务第一步:在线客服、在线帮助中心
  5. 易绝症员工事件始末:网易再发声明对时间线进行梳理
  6. 粉末冶金制品压制机器c语言编程,粉末冶金制品压制机控制.doc
  7. 自定义动画方法animate()
  8. 什么是状态化包过滤防火墙
  9. 避障算法 - VO、RVO 以及 ORCA (RVO2)[转载]
  10. 云运维拓扑图_云计算中心拓扑图