日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

如何优化代码和RAM大小

發(fā)布時(shí)間:2024/7/23 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何优化代码和RAM大小 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

如果供應(yīng)商為我自己的項(xiàng)目提供了一個(gè)起點(diǎn),那就太好了。工作'blinky'始終是一個(gè)偉大的首發(fā)。方便總是有代價(jià),而且“blinky”就是夸大“切換GPIO引腳”的代碼大小。對(duì)于具有少量RAM和FLASH的設(shè)備,這可能會(huì)引起關(guān)注:如果'blinky'占用那么多,我的應(yīng)用程序是否適合該設(shè)備?不要擔(dān)心:可以輕松地修剪掉(或任何其他項(xiàng)目)。

恩智浦LPC845-BRK主板上的Binky

我在這里使用一個(gè)'blinky'項(xiàng)目作為一個(gè)例子:修剪技巧也適用于任何其他類(lèi)型的項(xiàng)目。

在本教程中,我在BRK(突破)板上使用NXPLPC845:

恩智浦LPC845-BRK板

1Blinky示例

我所使用的是基于Eclipse的NXP MCUXpresso IDE:

選擇SDK板

我使用供應(yīng)商默認(rèn)設(shè)置創(chuàng)建了'blinky'項(xiàng)目:

Blinky項(xiàng)目

一個(gè)'blinky'應(yīng)該閃爍一個(gè)LED,對(duì)任何項(xiàng)目來(lái)說(shuō)都是一個(gè)好的開(kāi)手機(jī)。構(gòu)建相當(dāng)小的項(xiàng)目,代碼大小如下:

Memory region

Used Size

Region Size

%age Used

PROGRAM_FLASH:

10536 B

64 KB

16.08%

SRAM:

2424 B

16 KB

14.79%

text

data

bss

dec

hex

filename

10532

4

2420

12956

329c

lpc845breakout_led_blinky.axf

該信息也在控制臺(tái)中顯示,分為文本,數(shù)據(jù)和bss:

10K的'blinky'看起來(lái)有點(diǎn)夸張。但是我們現(xiàn)在將在接下來(lái)的步驟中修改它。

2、大小信息

有關(guān)大小信息的含義,請(qǐng)閱讀“?text,data和bss:Code and Data Size Explained?”。查看我的設(shè)備上使用空間的正常方法是檢查鏈接器映射文件(* .map):

鏈接器映射文件

但是這個(gè)map文件很難閱讀,而且對(duì)于專(zhuān)家來(lái)說(shuō)更是如此:它列出了具有地址和大小的部分:

鏈接器映射文件內(nèi)容

使用MCUXpresso IDE V11,有一個(gè)很好的“圖像信息”視圖,它基本上是一個(gè)更好的ma'p文件信息查看器:

圖像信息查看

我可以過(guò)濾和排序數(shù)據(jù),這讓我知道代碼和數(shù)據(jù)使用了多少空間:

圖像信息存儲(chǔ)器內(nèi)容

當(dāng)然,它需要一些關(guān)于應(yīng)用程序應(yīng)該做什么的知識(shí)。我總是瀏覽視圖中的項(xiàng)目列表,看看是否有任何我不希望的東西:也許應(yīng)用程序正在使用可以刪除的東西。

3、源代碼

對(duì)于一個(gè)簡(jiǎn)單的眨眼,這是相當(dāng)小的。首先要檢查程序正在做什么。main.c有這個(gè):

/* * Copyright 2017 NXP* All rights reserved.** SPDX-License-Identifier: BSD-3-Clause*/#include "board.h" #include "fsl_gpio.h"#include "pin_mux.h" /******************************************************************************** Definitions******************************************************************************/ #define BOARD_LED_PORT 1U#define BOARD_LED_PIN 2U /******************************************************************************** Prototypes******************************************************************************/ /******************************************************************************** Variables******************************************************************************/ volatile uint32_t g_systickCounter; /******************************************************************************** Code******************************************************************************/void SysTick_Handler(void) {if (g_systickCounter != 0U){g_systickCounter--;} }void SysTick_DelayTicks(uint32_t n) {g_systickCounter = n;while (g_systickCounter != 0U){} }/*! * @brief Main function */ int main(void) {/* Define the init structure for the output LED pin*/gpio_pin_config_t led_config = {kGPIO_DigitalOutput,0,};/* Board pin init */BOARD_InitPins();BOARD_InitBootClocks();BOARD_InitDebugConsole();/* Init output LED GPIO. */GPIO_PortInit(GPIO, BOARD_LED_PORT);GPIO_PinInit(GPIO, BOARD_LED_PORT, BOARD_LED_PIN, &led_config);/* Set systick reload value to generate 1ms interrupt */if (SysTick_Config(SystemCoreClock / 1000U)){while (1){}}while (1){/* Delay 1000 ms */SysTick_DelayTicks(1000U);GPIO_PortToggle(GPIO, BOARD_LED_PORT, 1u << BOARD_LED_PIN);} }

基本上,代碼正在初始化引腳,時(shí)鐘,設(shè)置SysTick定時(shí)器,然后在循環(huán)中執(zhí)行'blinky',使用Systick計(jì)數(shù)器延遲閃爍周期。

4、調(diào)試控制臺(tái)

但我可以看到它初始化一個(gè)調(diào)試控制臺(tái)(以及它的UART硬件):

BOARD_InitDebugConsole();

去掉這些,我們就可以得到:

Memory region

Used Size

Region Size

%age Used

PROGRAM_FLASH:

5616 B

64 KB

8.57%

SRAM:

2400 B

16 KB

14.65%

在許多情況下,演示應(yīng)用程序會(huì)設(shè)置一些通信通道,但之后就不會(huì)使用它們。鏈接器可以很好地刪除未使用的對(duì)象(函數(shù)/變量),但前提是它們沒(méi)有被引用。

5、半主控和printf()

接下來(lái)要看的是是否存在任何半主機(jī)或printf()。該項(xiàng)目正在使用'Redlib',這是一個(gè)優(yōu)化的庫(kù),與'標(biāo)準(zhǔn)'newlib或較小標(biāo)準(zhǔn)的newlib-nano相比:

Redlib

盡管如此,該庫(kù)可能會(huì)增加代碼大小,因?yàn)樗褂冒胫鳈C(jī)(通過(guò)調(diào)試器發(fā)送消息)。查看Memory視圖,我可以直接或間接地看到所需的所有這些標(biāo)準(zhǔn)I / O函數(shù):

stdio功能

擁有該功能的所有鉤子只有在使用它時(shí)才有意義,并且“blinky”不會(huì)使用它。因此,擺脫半主機(jī)和所有未使用的標(biāo)準(zhǔn)I / O意味著使用'none'變體:

沒(méi)有標(biāo)準(zhǔn)I / O的庫(kù)

這讓我們了解到這一點(diǎn):

Memory region

Used Size

Region Size

%age Used

PROGRAM_FLASH:

3372 B

64 KB

5.15%

SRAM:

2208 B

16 KB

13.48%

?

或者使用較小的變體或?qū)崿F(xiàn)。有關(guān)此問(wèn)題的更多背景信息,請(qǐng)參閱本文末尾的鏈接。

6DEBUGNDEBUG

接下來(lái)要檢查編譯器是否定義了列出的DEBUG。事實(shí)上,情況就是這樣:

DEBUG定義

使用該定義集,SDK和示例驅(qū)動(dòng)程序中有許多額外的代碼,它們使用'assert()'宏檢查好的值:

SDK代碼中斷言的用法

在這里,圖像信息視圖再次有用:它向我展示了使用assert()的所有地方:

斷言用法

實(shí)際上,在代碼中使用斷言來(lái)盡早捕獲編程錯(cuò)誤是一種很好的做法。但是所有的assert()代碼確實(shí)加起來(lái)了。要關(guān)閉額外的代碼(和安全帶!),我將宏更改為NDEBUG:

NDEBUG

這讓我們了解到一點(diǎn):

Memory region

Used Size

Region Size

%age Used

PROGRAM_FLASH:

3144 B

64 KB

4.80%

SRAM:

2208 B

16 KB

13.48%

7、中斷和向量

圖像信息視圖再次是一個(gè)很好的起點(diǎn)。我正在檢查使用過(guò)的中斷。Blinky正在使用預(yù)期的SysTick中斷。但是仍然使用UART中斷?

使用中斷

大多數(shù)中斷都實(shí)現(xiàn)為“weak”:實(shí)現(xiàn)為默認(rèn)/空,可以被應(yīng)用程序覆蓋。但UART沒(méi)有意義,因?yàn)椤眀linky”沒(méi)有使用任何UART通信?

事實(shí)證明,NXP SDK默認(rèn)啟用了UART事務(wù)API:

UART Transactional API設(shè)置

事務(wù)API允許在通信組塊/事務(wù)中發(fā)送/接收UART數(shù)據(jù)。但我們不需要在我們的眨眼中,所以讓我們把它關(guān)掉:

關(guān)閉UART TransactionalAPI

這樣一來(lái),內(nèi)存情況為:

Memory region

Used Size

Region Size

%age Used

PROGRAM_FLASH:

2964 B

64 KB

4.52%

SRAM:

2184 B

16 KB

13.33%

但我認(rèn)為CMSIS(設(shè)置中斷優(yōu)先級(jí),通用時(shí)鐘設(shè)置)非常有用,所以我不在這里觸摸它。應(yīng)用程序中最大的功能是SysTick代碼用來(lái)將定時(shí)器的優(yōu)先級(jí)設(shè)置為最低優(yōu)先級(jí),以節(jié)省另外220個(gè)字節(jié):

CMSIS作為最大的單一功能代碼大小貢獻(xiàn)者

8、優(yōu)化

到目前為止,我已經(jīng)刪除了不需要的或未使用的功能。接下來(lái)我可以打開(kāi)編譯器優(yōu)化。默認(rèn)情況下,項(xiàng)目設(shè)置為-O0:

編譯器優(yōu)化

-O0表示無(wú)優(yōu)化:代碼直觀且易于調(diào)試。

-O1主要優(yōu)化函數(shù)進(jìn)入/退出代碼,并且能夠在不影響調(diào)試的情況下減少代碼大小。在這個(gè)例子中,它將代碼大小減少了一半!

?

Memory region

Used Size

Region Size

%age Used

PROGRAM_FLASH:

1540 B

64 KB

2.35%

SRAM:

2184 B

16 KB

13.33%

-O2優(yōu)化更多并盡可能地將事物保存在寄存器中。因?yàn)閼?yīng)用程序中的功能相當(dāng)小,所以改進(jìn)并不大:

Memory region

Used Size

Region Size

%age Used

PROGRAM_FLASH:

1516 B

64 KB

2.31%

SRAM:

2184 B

16 KB

13.33%

-O3通過(guò)額外的內(nèi)聯(lián)優(yōu)化最佳。-O3的目標(biāo)是速度,所以難怪代碼大小再次增加:

Memory region

Used Size

Region Size

%age Used

PROGRAM_FLASH:

1792 B

64 KB

2.73%

SRAM:

2184 B

16 KB

13.33%

代碼大小優(yōu)化的最佳選擇是-Os(針對(duì)大小進(jìn)行優(yōu)化):

Memory region

Used Size

Region Size

%age Used

PROGRAM_FLASH:

1456 B

64 KB

2.22%

SRAM:

2184 B

16 KB

13.33%

現(xiàn)在看起來(lái)很合理!當(dāng)然現(xiàn)在有一些方法可以為“裸露的裸眼”切斷更多,但是現(xiàn)有的一切(啟動(dòng)代碼,時(shí)鐘和GPIO初始化)對(duì)于真正的應(yīng)用程序是有意義的,所以我現(xiàn)在停在這里。

9RAM:堆和堆棧

看起來(lái)不正確的是SRAM的使用。'heap'使用了一大塊:

堆內(nèi)存使用情況

該堆用于動(dòng)態(tài)內(nèi)存分配(malloc())。嵌入式編程的一般規(guī)則是避免它。但它默認(rèn)在這里。它可以在鏈接器設(shè)置中關(guān)閉:演示使用1K用于堆和堆棧。由于我沒(méi)有使用malloc(),我可以將堆大小設(shè)置為0x0。對(duì)于真正依賴于應(yīng)用程序的保留堆棧。在ARM Cortex上,MSP用于啟動(dòng)/主控和中斷(參見(jiàn)“?ARMCortex-M中斷和FreeRTOS?”)。0x100(256字節(jié))應(yīng)該足夠我的眨眼。

堆和堆棧大小

這讓我了解到一點(diǎn):

Memory region

Used Size

Region Size

%age Used

PROGRAM_FLASH:

1456 B

64 KB

2.22%

SRAM:

392 B

16 KB

2.39%

如果它是關(guān)于進(jìn)一步減小堆棧大小,我可以查看調(diào)用圖信息,它給出了有關(guān)使用多少堆棧空間的信息:

堆棧大小的圖形顯示

有一些項(xiàng)目的大小信息未知(標(biāo)有“?”)因?yàn)樗鼈冊(cè)趲?kù)中。驗(yàn)證實(shí)際堆棧使用情況的方法是編寫(xiě)模式(例如0xffff'ffff),然后運(yùn)行應(yīng)用程序一段時(shí)間:

使用的堆棧

這表明實(shí)際使用了72個(gè)字節(jié)。有一點(diǎn)余地,在這種情況下將堆棧大小設(shè)置為128字節(jié)看起來(lái)是合理的。這給出了:

Memory region

Used Size

Region Size

%age Used

PROGRAM_FLASH:

1456 B

64 KB

2.22%

SRAM:

264 B

16 KB

1.61%

堆棧溢出可能是嵌入式應(yīng)用程序中最常見(jiàn)的問(wèn)題。如果可以的話,可以為堆棧提供盡可能多的RAM。如果縮小尺寸,請(qǐng)確保進(jìn)行了足夠的分析以證明堆疊尺寸合理。

10MTB

剩下的一件事就是使用RAM空間:MTB緩沖區(qū)。微跟蹤緩沖區(qū)用于跟蹤,這非常有用(請(qǐng)參閱“?使用MTB跟蹤調(diào)試ARM Cortex-M0 +硬故障?”)。可以使用宏禁用緩沖區(qū):

mtb.c

__MTB_DISABLE

這讓我對(duì)此:

Memory region

Used Size

Region Size

%age Used

PROGRAM_FLASH:

1456 B

64 KB

2.22%

SRAM:

136 B

16 KB

0.83%

我想在這里我們可以很開(kāi)心

11、摘要

供應(yīng)商的例子很棒:它們給了我一個(gè)很好的起點(diǎn)。它們沒(méi)有經(jīng)過(guò)優(yōu)化,這是故意的。但它們可能帶有我不需要的功能和功能。了解使用切斷功能或調(diào)整設(shè)置來(lái)優(yōu)化應(yīng)用程序的不同方法對(duì)于優(yōu)化RAM和FLASH使用非常有用。在本教程中,我展示了如何將'blinky'降低到大約1KB閃存和大約136字節(jié)的SRAM。當(dāng)然這一切都取決于功能和用法,但我認(rèn)為現(xiàn)在為我的應(yīng)用程序添加額外的功能是一個(gè)非常合理的狀態(tài)。

我希望這些提示可能對(duì)您的項(xiàng)目有用。

12、鏈接

  • 文本,數(shù)據(jù)和bss:代碼和數(shù)據(jù)大小說(shuō)明
  • 拆箱恩智浦LPC845-BRK板
  • 教程:使用恩智浦LPC845-BRK主板閃爍
  • 使用恩智浦Kinetis SDK V2.0進(jìn)行半主機(jī)(再次!)
  • 為什么我不喜歡printf()
  • XFormat,輕量級(jí)printf()和sprintf()替代品
  • 優(yōu)化Kinetis gcc啟動(dòng)
  • 新的恩智浦MCUXpresso Eclipse IDE v11.0

聲明: 此篇由 Erich Styger的《Tutorial: How to Optimize Code and RAM?Size》翻譯。原文地址為:https://mcuoneclipse.com/2019/08/17/tutorial-how-to-optimize-code-and-ram-size/。權(quán)屬歸原作者所有。

歡迎關(guān)注:

總結(jié)

以上是生活随笔為你收集整理的如何优化代码和RAM大小的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。