<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【LVGL】?jī)?nèi)存分配管理(與 sct 文件配合管理)

      引言

      LVGL 內(nèi)存管理,可選默認(rèn) lvgl 管理方式,也可選自定義管理方式。

      LVGL 內(nèi)存消耗

      這里說的內(nèi)存管理,就是指“LVGL 要管理的內(nèi)存”。
      這個(gè)內(nèi)存池不能分配的過大,過大則圖形緩沖區(qū)其他被分配的位置就可能不足;也不能過小,過小則可能分配給某些控件的內(nèi)存不足。所以需要合理配需要管理的內(nèi)存池的大小

      PixPin_2025-11-05_16-56-23

      內(nèi)存管理文件添加

      在工程中選擇一個(gè)合適的文件夾下添加 malloc.c 和 malloc.h 文件,方便添加管理代碼。
      由于我使用的 arm 為 stm32h743iit6 型號(hào)的單片機(jī),其內(nèi)存分布如下 sct 文件所示:
      其默認(rèn)未初始化的變量都是放到 AXI SRAM 區(qū)的,我們一般也是將 lvgl 需要管理的內(nèi)存放到這個(gè)區(qū)域,所以在后面 malloc.c 文件中不需要 _attribute_,直接為默認(rèn)內(nèi)存即可。

      這個(gè)內(nèi)存管理文件原本是正點(diǎn)原子寫來管理整個(gè)工程的內(nèi)存的,但是由于我們已經(jīng)使用了 sct 靜態(tài)內(nèi)存管理的方法,所以這里的內(nèi)存管理文件僅僅當(dāng)作 lvgl 的內(nèi)存管理文件使用了,所以需要初始化的內(nèi)存區(qū)域也只有內(nèi)部的 SRAM 區(qū),外部 SDRAM 的管理用 sct 文件即可。

      PixPin_2025-11-05_17-05-27

      malloc.c

      點(diǎn)擊查看代碼
      #include "malloc.h"
      
      /* 內(nèi)存池(32字節(jié)對(duì)齊) */
      static __ALIGNED(32) uint8_t mem1base[MEM1_MAX_SIZE]; /* 內(nèi)部SRAM內(nèi)存池 */
      // static __ALIGNED(32) uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((section(".RAM_SDRAM"))); /* 外部SDRAM內(nèi)存池 */
      
      /* 內(nèi)存管理表 */
      static MT_TYPE mem1mapbase[MEM1_ALLOC_TABLE_SIZE]; /* 內(nèi)部SRAM內(nèi)存池MAP */
      // static MT_TYPE mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((section(".RAM_SDRAM"))); /* 外部SRAM內(nèi)存池MAP */
      
      /* 內(nèi)存管理參數(shù) */
      const uint32_t memtblsize[SRAMBANK] = {
          MEM1_ALLOC_TABLE_SIZE,
          // MEM2_ALLOC_TABLE_SIZE
      }; /* 內(nèi)存表大小 */
      const uint32_t memblksize[SRAMBANK] = {
          MEM1_BLOCK_SIZE,
          // MEM2_BLOCK_SIZE
      }; /* 內(nèi)存分塊大小 */
      const uint32_t memsize[SRAMBANK] = {
          MEM1_MAX_SIZE,
          // MEM2_MAX_SIZE
      }; /* 內(nèi)存總大小 */
      
      /* 內(nèi)存管理控制器 */
      struct _m_mallco_dev mallco_dev =
          {
              my_mem_init,    /* 內(nèi)存初始化 */
              my_mem_perused, /* 內(nèi)存使用率 */
              /* 內(nèi)存池 */
              mem1base,
              // mem2base,
              /* 內(nèi)存管理狀態(tài)表 */
              mem1mapbase,
              // mem2mapbase,
              /* 內(nèi)存管理未就緒 */
              0,
              // 0,
      };
      
      /**
       * @brief       復(fù)制內(nèi)存
       * @param       *des : 目的地址
       * @param       *src : 源地址
       * @param       n    : 需要復(fù)制的內(nèi)存長(zhǎng)度(字節(jié)為單位)
       * @retval      無
       */
      void my_mem_copy(void *des, void *src, uint32_t n)
      {
          uint8_t *xdes = des;
          uint8_t *xsrc = src;
          while (n--)
              *xdes++ = *xsrc++;
      }
      
      /**
       * @brief       設(shè)置內(nèi)存值
       * @param       *s    : 內(nèi)存首地址
       * @param       c     : 要設(shè)置的值
       * @param       count : 需要設(shè)置的內(nèi)存大小(字節(jié)為單位)
       * @retval      無
       */
      void my_mem_set(void *s, uint8_t c, uint32_t count)
      {
          uint8_t *xs = s;
          while (count--)
              *xs++ = c;
      }
      
      /**
       * @brief       內(nèi)存管理初始化
       * @param       memx : 所屬內(nèi)存塊
       * @retval      無
       */
      void my_mem_init(uint8_t memx)
      {
          my_mem_set(mallco_dev.memmap[memx], 0, memtblsize[memx] * 4); /* 內(nèi)存狀態(tài)表數(shù)據(jù)清零 */
          mallco_dev.memrdy[memx] = 1;                                  /* 內(nèi)存管理初始化OK */
      }
      
      /**
       * @brief       獲取內(nèi)存使用率
       * @param       memx : 所屬內(nèi)存塊
       * @retval      使用率(擴(kuò)大了10倍,0~1000,代表0.0%~100.0%)
       */
      uint16_t my_mem_perused(uint8_t memx)
      {
          uint32_t used = 0;
          uint32_t i;
      
          for (i = 0; i < memtblsize[memx]; i++)
          {
              if (mallco_dev.memmap[memx][i])
                  used++;
          }
      
          return (used * 1000) / (memtblsize[memx]);
      }
      
      /**
       * @brief       內(nèi)存分配(內(nèi)部調(diào)用)
       * @param       memx : 所屬內(nèi)存塊
       * @param       size : 要分配的內(nèi)存大小(字節(jié))
       * @retval      內(nèi)存偏移地址
       *   @arg       0 ~ 0xFFFFFFFE : 有效的內(nèi)存偏移地址
       *   @arg       0xFFFFFFFF     : 無效的內(nèi)存偏移地址
       */
      uint32_t my_mem_malloc(uint8_t memx, uint32_t size)
      {
          signed long offset = 0;
          uint32_t nmemb;     /* 需要的內(nèi)存塊數(shù) */
          uint32_t cmemb = 0; /* 連續(xù)空內(nèi)存塊數(shù) */
          uint32_t i;
      
          if (!mallco_dev.memrdy[memx])
          {
              mallco_dev.init(memx); /* 未初始化,先執(zhí)行初始化 */
          }
          if (size == 0)
              return 0XFFFFFFFF;           /* 不需要分配 */
          nmemb = size / memblksize[memx]; /* 獲取需要分配的連續(xù)內(nèi)存塊數(shù) */
      
          if (size % memblksize[memx])
              nmemb++;
      
          for (offset = memtblsize[memx] - 1; offset >= 0; offset--) /* 搜索整個(gè)內(nèi)存控制區(qū) */
          {
              if (!mallco_dev.memmap[memx][offset])
              {
                  cmemb++; /* 連續(xù)空內(nèi)存塊數(shù)增加 */
              }
              else
              {
                  cmemb = 0; /* 連續(xù)內(nèi)存塊清零 */
              }
      
              if (cmemb == nmemb) /* 找到了連續(xù)nmemb個(gè)空內(nèi)存塊 */
              {
                  for (i = 0; i < nmemb; i++) /* 標(biāo)注內(nèi)存塊非空  */
                  {
                      mallco_dev.memmap[memx][offset + i] = nmemb;
                  }
      
                  return (offset * memblksize[memx]); /* 返回偏移地址  */
              }
          }
      
          return 0XFFFFFFFF; /* 未找到符合分配條件的內(nèi)存塊 */
      }
      
      /**
       * @brief       釋放內(nèi)存(內(nèi)部調(diào)用)
       * @param       memx   : 所屬內(nèi)存塊
       * @param       offset : 內(nèi)存地址偏移
       * @retval      釋放結(jié)果
       *   @arg       0, 釋放成功;
       *   @arg       1, 釋放失敗;
       *   @arg       2, 超區(qū)域了(失敗);
       */
      uint8_t my_mem_free(uint8_t memx, uint32_t offset)
      {
          int i;
      
          if (!mallco_dev.memrdy[memx]) /* 未初始化,先執(zhí)行初始化 */
          {
              mallco_dev.init(memx);
              return 1; /* 未初始化 */
          }
      
          if (offset < memsize[memx]) /* 偏移在內(nèi)存池內(nèi). */
          {
              int index = offset / memblksize[memx];      /* 偏移所在內(nèi)存塊號(hào)碼 */
              int nmemb = mallco_dev.memmap[memx][index]; /* 內(nèi)存塊數(shù)量 */
      
              for (i = 0; i < nmemb; i++) /* 內(nèi)存塊清零 */
              {
                  mallco_dev.memmap[memx][index + i] = 0;
              }
      
              return 0;
          }
          else
          {
              return 2; /* 偏移超區(qū)了. */
          }
      }
      
      /**
       * @brief       釋放內(nèi)存(外部調(diào)用)
       * @param       memx : 所屬內(nèi)存塊
       * @param       ptr  : 內(nèi)存首地址
       * @retval      無
       */
      void myfree(uint8_t memx, void *ptr)
      {
          uint32_t offset;
      
          if (ptr == NULL)
              return; /* 地址為0. */
      
          offset = (uint32_t)ptr - (uint32_t)mallco_dev.membase[memx];
          my_mem_free(memx, offset); /* 釋放內(nèi)存 */
      }
      
      /**
       * @brief       分配內(nèi)存(外部調(diào)用)
       * @param       memx : 所屬內(nèi)存塊
       * @param       size : 要分配的內(nèi)存大小(字節(jié))
       * @retval      分配到的內(nèi)存首地址.
       */
      void *mymalloc(uint8_t memx, uint32_t size)
      {
          uint32_t offset;
          offset = my_mem_malloc(memx, size);
      
          if (offset == 0xFFFFFFFF) /* 申請(qǐng)出錯(cuò) */
          {
              return NULL; /* 返回空(0) */
          }
          else /* 申請(qǐng)沒問題, 返回首地址 */
          {
              return (void *)((uint32_t)mallco_dev.membase[memx] + offset);
          }
      }
      
      /**
       * @brief       重新分配內(nèi)存(外部調(diào)用)
       * @param       memx : 所屬內(nèi)存塊
       * @param       *ptr : 舊內(nèi)存首地址
       * @param       size : 要分配的內(nèi)存大小(字節(jié))
       * @retval      新分配到的內(nèi)存首地址.
       */
      void *myrealloc(uint8_t memx, void *ptr, uint32_t size)
      {
          uint32_t offset;
          offset = my_mem_malloc(memx, size);
      
          if (offset == 0xFFFFFFFF) /* 申請(qǐng)出錯(cuò) */
          {
              return NULL; /* 返回空(0) */
          }
          else /* 申請(qǐng)沒問題, 返回首地址 */
          {
              my_mem_copy((void *)((uint32_t)mallco_dev.membase[memx] + offset), ptr, size); /* 拷貝舊內(nèi)存內(nèi)容到新內(nèi)存 */
              myfree(memx, ptr);                                                             /* 釋放舊內(nèi)存 */
              return (void *)((uint32_t)mallco_dev.membase[memx] + offset);                  /* 返回新內(nèi)存首地址 */
          }
      }
      
      /**
       * @brief       分配內(nèi)存(外部調(diào)用)
       * @param       size : 要分配的內(nèi)存大小(字節(jié))
       * @retval      分配到的內(nèi)存首地址.
       */
      void *lv_mymalloc(uint32_t size)
      {
          return (void *)mymalloc(SRAM, size);
      }
      
      /**
       * @brief       釋放內(nèi)存(外部調(diào)用)
       * @param       ptr  : 內(nèi)存首地址
       * @retval      無
       */
      void lv_myfree(void *ptr)
      {
          myfree(SRAM, ptr);
      }
      
      /**
       * @brief       重新分配內(nèi)存(外部調(diào)用)
       * @param       *ptr : 舊內(nèi)存首地址
       * @param       size : 要分配的內(nèi)存大小(字節(jié))
       * @retval      新分配到的內(nèi)存首地址.
       */
      void *lv_myrealloc(void *ptr, uint32_t size)
      {
          return (void *)myrealloc(SRAM, ptr, size);
      }
      

      malloc.h

      點(diǎn)擊查看代碼
      #ifndef __MALLOC_H
      #define __MALLOC_H
      
      #include "headers.h"
      
      #ifndef NULL
      #define NULL 0
      #endif
      
      /* 定義三個(gè)內(nèi)存池 */
      #define SRAM 0  /* 內(nèi)部?jī)?nèi)存池 */
      #define SDRAM 1 /* CCM內(nèi)存池(此部分SRAM僅僅CPU可以訪問!!!) */
      
      /* 定義內(nèi)存管理表類型,當(dāng)外擴(kuò)SDRAM的時(shí)候,必須使用uint32_t類型,否則可以定義成uint16_t,以節(jié)省內(nèi)存占用 */
      #define MT_TYPE uint32_t
      
      #define SRAMBANK 1 /* 定義支持的SRAM塊數(shù). */
      
      /* mem1內(nèi)存參數(shù)設(shè)定.mem1完全處于內(nèi)部SRAM里面. */
      #define MEM1_BLOCK_SIZE 64                                    /* 內(nèi)存塊大小為 64 字節(jié) */
      #define MEM1_MAX_SIZE 200 * 1024                              /* 最大管理內(nèi)存 512K */
      #define MEM1_ALLOC_TABLE_SIZE MEM1_MAX_SIZE / MEM1_BLOCK_SIZE /* 內(nèi)存表大小 */
      
      // /* mem2內(nèi)存參數(shù)設(shè)定.mem2處于CCM,用于管理CCM(特別注意,這部分SRAM,僅CPU可以訪問!!) */
      // #define MEM2_BLOCK_SIZE 64                                    /* 內(nèi)存塊大小為 64 字節(jié) */
      // #define MEM2_MAX_SIZE 60 * 1024                               /* 最大管理內(nèi)存 32MB */
      // #define MEM2_ALLOC_TABLE_SIZE MEM2_MAX_SIZE / MEM2_BLOCK_SIZE /* 內(nèi)存表大小 */
      
      /* 內(nèi)存管理控制器 */
      struct _m_mallco_dev
      {
          void (*init)(uint8_t);        /* 初始化 */
          uint16_t (*perused)(uint8_t); /* 內(nèi)存使用率 */
          uint8_t *membase[SRAMBANK];   /* 內(nèi)存池 管理SRAMBANK個(gè)區(qū)域的內(nèi)存 */
          uint32_t *memmap[SRAMBANK];   /* 內(nèi)存管理狀態(tài)表 */
          uint8_t memrdy[SRAMBANK];     /* 內(nèi)存管理是否就緒 */
      };
      
      extern struct _m_mallco_dev mallco_dev; /* 在mallco.c里面定義 */
      
      void my_mem_set(void *s, uint8_t c, uint32_t count); /* 設(shè)置內(nèi)存 */
      void my_mem_copy(void *des, void *src, uint32_t n);  /* 復(fù)制內(nèi)存 */
      void my_mem_init(uint8_t memx);                      /* 內(nèi)存管理初始化函數(shù)(外/內(nèi)部調(diào)用) */
      uint32_t my_mem_malloc(uint8_t memx, uint32_t size); /* 內(nèi)存分配(內(nèi)部調(diào)用) */
      uint8_t my_mem_free(uint8_t memx, uint32_t offset);  /* 內(nèi)存釋放(內(nèi)部調(diào)用) */
      uint16_t my_mem_perused(uint8_t memx);               /* 獲得內(nèi)存使用率(外/內(nèi)部調(diào)用)  */
      
      /* 用戶調(diào)用函數(shù) */
      void myfree(uint8_t memx, void *ptr);                    /* 內(nèi)存釋放(外部調(diào)用) */
      void *mymalloc(uint8_t memx, uint32_t size);             /* 內(nèi)存分配(外部調(diào)用) */
      void *myrealloc(uint8_t memx, void *ptr, uint32_t size); /* 重新分配內(nèi)存(外部調(diào)用) */
      
      void *lv_mymalloc(uint32_t size);
      void lv_myfree(void *ptr);
      void *lv_myrealloc(void *ptr, uint32_t size);
      #endif
      
      

      lv_conf.h 修改

      找到MEMORY SETTINGS位置,

      1. LV_MEMCUSTOM宏定義修改為 1,即指定自定義內(nèi)存分配管理方式
      2. 將下圖紅框中的 malloc、free、realloc 修改成 malloc.c 文件中的 lv_mymalloc、lv_myfree、lv_myrealloc,并且將應(yīng)用的頭文件改為"malloc.h"

      PixPin_2025-11-05_17-21-53

      測(cè)試

      我這里測(cè)試的是 music 的 demo,是一個(gè)較大的 demo,我們可以通過修改 malloc.h 文件中的內(nèi)存分配位置(下圖所示),來管理分配給 lvgl 管理的內(nèi)存,將其改為不同大小可以看到不同效果,那么就是管理成功了(由于此 demo 較大,則需要分配較大的內(nèi)存,例如 200K 才能正常運(yùn)行)。
      PixPin_2025-11-05_17-25-16

      main.c 調(diào)用

      在 main 函數(shù)中調(diào)用 my_mem_init(SRAM);初始化即可(非必要)。

      點(diǎn)擊查看代碼
      int main(void)
      {
      
        /* USER CODE BEGIN 1 */
      
        /* USER CODE END 1 */
      
        /* MPU Configuration--------------------------------------------------------*/
        MPU_Config();
      
        /* Enable the CPU Cache */
      
        /* 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 */
      
        /* 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();
        MX_FMC_Init();
        MX_LTDC_Init();
        MX_DMA2D_Init();
        MX_TIM1_Init();
        /* USER CODE BEGIN 2 */
        /****************** 初始化打印 ******************/
        Set_Current_USART(USART1_IDX);   // 設(shè)置當(dāng)前使用的USART為USART1
        printf("SDRAM 初始化通過!\r\n"); // 打印SDRAM初始化成功信息
        /****************** 初始化操作 ******************/
        delay_init(480); // 初始化延時(shí)函數(shù),參數(shù)為系統(tǒng)時(shí)鐘頻率MHz
        my_mem_init(SRAM);
        //  lcd_init();      // 初始化LCD顯示控制器
        //  gtxxxx_init();   // 初始化觸摸屏控制器 GTXXXX
        /* lvgl */
        btim_timx_int_init(2400 - 1, 100 - 1); // 基本定時(shí)器TIMX定時(shí)中斷初始化,1ms中斷一次
        lv_init();                             // 初始化LVGL庫
        lv_port_disp_init();                   // 初始化LVGL顯示端口
        lv_port_indev_init();                  // 初始化LVGL輸入設(shè)備端口
        // lv_obj_t *switch_obj = lv_switch_create(lv_scr_act()); // 創(chuàng)建一個(gè)開關(guān)對(duì)象
        // lv_obj_set_size(switch_obj, 120, 60);                  // 設(shè)置開關(guān)對(duì)象的大小為120x60像素
        // lv_obj_align(switch_obj, LV_ALIGN_CENTER, 0, 0);       // 將開關(guān)對(duì)象對(duì)齊到屏幕中心
        /* demo */
        // lv_demo_stress();
        lv_demo_music();
        /* USER CODE END 2 */
      
        /* Infinite loop */
        /* USER CODE BEGIN WHILE */
        while (1)
        {
          // lcd_test();
          // gtxxxx_scan(); // 觸摸屏掃描測(cè)試,帶坐標(biāo)返回
          /* lvgl */
          delay_ms(5);
          lv_timer_handler(); /* LVGL任務(wù)處理 */
          /* USER CODE END WHILE */
      
          /* USER CODE BEGIN 3 */
        }
        /* USER CODE END 3 */
      }
      

      MEM1_MAX_SIZE 修改為 40 * 1024 效果

      可以看到,就只有白屏,因?yàn)閮H僅初始化了 lcd 后,給 lvgl 后續(xù)的圖片即控件什么的分配的內(nèi)存不足,就只能顯示白屏了。
      4a5fcc7dc50d2e3479f7aa6abe229a31

      MEM1_MAX_SIZE 修改為 200 * 1024 效果

      200KB 分配的內(nèi)存剛好,正常運(yùn)行。
      40d1d865361493de3721d2e8029d37d7

      MEM1_MAX_SIZE 修改為 500 * 1024 效果

      某些緩存內(nèi)存不足,直接在初始化前就進(jìn)入了內(nèi)存錯(cuò)誤中斷,只能看到黑屏,甚至沒有背光。
      074f99b22ad85d996979945cf69fa6b4

      博客導(dǎo)航

      博客導(dǎo)航

      posted @ 2025-11-05 17:34  膝蓋中箭衛(wèi)兵  閱讀(7)  評(píng)論(0)    收藏  舉報(bào)
      ORCID iD icon https://orcid.org/0000-0001-5102-772X
      主站蜘蛛池模板: 国产69精品久久久久乱码免费| 泰州市| 亚洲精品尤物av在线网站| 亚洲伊人成无码综合网| 国产精品一区二区久久毛片| 久久青草国产精品一区| 色欲色香天天天综合网站免费| 国产精品久久毛片av大全日韩| 92国产精品午夜福利| 中文字幕日韩精品人妻| 精品国产一区av天美传媒| 国产一区二区三区尤物视频| 精品少妇av蜜臀av| 日韩精品中文字幕人妻| 久久99精品久久久久久| 国产黄色免费看| 日日碰狠狠添天天爽超碰97| 国产精品va无码一区二区| 精品久久亚洲中文无码| 欧美成人精品手机在线| 平舆县| 亚洲一区二区三区| 内地自拍三级在线观看| 国产一区二区不卡在线| 国产精品男女爽免费视频| 欧美成人片在线观看| 自拍偷拍第一区二区三区| 精品国产粉嫩一区二区三区| 亚洲av专区一区| 一区二区三区四区五区自拍| 日韩高清亚洲日韩精品一区二区 | 日韩av天堂综合网久久| 国产综合久久99久久| 久久天天躁夜夜躁狠狠综合| 国产一级av在线播放| 日韩人妻一区中文字幕| 欧美一本大道香蕉综合视频| 在线观看潮喷失禁大喷水无码| 国产精品播放一区二区三区| 中文字幕国产日韩精品| 色噜噜亚洲男人的天堂|