題:
壓縮.hex文件用於微控制器
Danial
2019-10-12 15:53:18 UTC
view on stackexchange narkive permalink

我目前正在 AVR Studio 中編寫程序,這是內部版本* Memory的使用情況:*

 設備:atmega32
    程序:9304字節(已滿28.4%)
    (.text + .data + .bootloader)
    數據:334字節(已滿16.3%)
    (.data + .bss + .noinit)
 

當我使用 ATmega32 微型控制器時,似乎沒有問題,但是我想使用相同的代碼並用於 ATmega8 微型控制器-控制器。

所以我想減小程序的大小,使其小於8192 bytes

我該怎麼做?

您正在使用浮點庫嗎?
@Danial不能解決您的問題,但是我只注意到.hex文件只是一種用於存儲程序代碼的格式。它們只是文本,因此可以很好地壓縮。但這不是最終出現在MCU閃存中的,而是實際的程序代碼。所以,這就是您要縮小的大小,而不是.hex文件。
七 答案:
Oldfart
2019-10-12 15:59:56 UTC
view on stackexchange narkive permalink

您可以 壓縮十六進制代碼,只能嘗試減少它。

  • 嘗試其他?編譯器設置(最大程度地優化和優化大小)
  • 選擇源代碼,查看可以優化或省略的內容。
  • 查看是否引入了不必要的庫代碼。(不應,但是誰知道)

Jeroen3的優點:檢查是否需要/具有浮點數。尤其是像 printf 這樣的函數有時會引入浮點代碼,以便能夠處理 printf(“%f” ... 。不需要。

Michel Keijzers
2019-10-12 16:04:03 UTC
view on stackexchange narkive permalink

MCU無法執行壓縮代碼。

但是,您可以做一些事情:

  • 不要使用完整的庫函數,而是自己創建部分或全部函數;通過這種方式,您可以優化大多數(過於)靈活的庫函數來滿足您的特定需求。
  • 刪除您自己代碼中的重複代碼。對幾乎重複的代碼使用參數,使其更靈活。
  • 將最小類型用於常量,尤其是常量數組。
  • 刪除“明顯的”無效代碼(永遠無法執行的代碼),請參閱下面有關Jeroen3和Dakkaron的說明。(檢查這是針對全部功能還是部分功能)。另請參見此鏈接
  • 減少字符串(如果使用大量打印語句,請盡可能減少這些常量字符串)。
刪除無效代碼是[鏈接器功能](https://renenyffenegger.ch/notes/development/languages/CC-plus-plus/GCC/options/Wl/index):**-Wl,--gc-sections **也適用於未使用的庫函數。
@Jeroen3謝謝,我不知道它是如此智能。我更新了答案(對您的名字進行了評論)。
@Jeroen3這僅適用於“硬”死代碼,因此編譯器可以在其中推斷出死代碼的代碼。它不適用於編譯器無法確定的無效代碼,例如一些僅在使用特定參數調用該函數時才執行的代碼,但絕不會使用該參數調用該函數。因此,使用鏈接器檢查絕對有用,但是對於死代碼手工分析代碼也很有用。
@Dakkaron謝謝...我在註釋中添加了您的名字(實際上,我的名字和您以前寫的一樣)。
Michael Karas
2019-10-12 19:41:12 UTC
view on stackexchange narkive permalink

除了此處其他答案中提供的出色建議之外,我想評論一下,編譯器(和鏈接器)可以優化代碼的數量可能有很大的差異。

幾年前,我在一家公司使用ATMega8的公司工作。當我到達現場時,該產品具有三種不同的源代碼構建,可以為各種產品配置提供單獨的功能集。源代碼使用低成本的C編譯器進行編譯,每個代碼集幾乎都無法容納設備FLASH存儲器的8K字節。

我讓公司從AVR社區中知名的公司購買了高端編譯器。然後,我開始研究軟件源代碼,並設置編譯器選項以實現最大程度的優化。

當我完成工作時,所有產品選項都適合一個小於8K字節的圖像。實際上,我有足夠的空間在代碼中添加僅傳輸軟件UART,以使該軟件可以散佈用於幫助校準產品參數的內部信息。當通過分壓器將28V信號施加到A / D通道之一時,將觸發UART輸出。之所以需要觸發器,是因為軟件UART輸出使用的GPIO通常是產品輸出的信號。

好故事。編譯器可以做一些出色的工作,但是人工可以幫助您。我以類似的方式從客戶那裡接管了一個項目,該項目使用的是8位PIC處理器,客戶將不同的版本分為三個相似的源代碼-每個版本的程序存儲器都已滿(8k程序存儲器,約佔85%)。我合併了代碼,通過檢查生成的彙編代碼來優化C代碼本身,並隨著時間的推移添加了許多功能(大約98%的已滿)。扔一個更好的編譯器可能會有所幫助,但不能達到代碼優化的程度。
Graham
2019-10-13 01:02:23 UTC
view on stackexchange narkive permalink

任何類型的優化的第一步是 查找正在做的事情

您的第一步應該是使鏈接器轉儲構建中每個標識符的地址。這就是所有函數和所有變量。您的鏈接器還應該能夠報告功能的大小。它可能不會使用變量大小,但是您可以從列表中下一個變量的地址推斷出這些大小。

一旦您知道空間的去向,就可以對此做些事情。當您開始研究最大的解決方案時,解決方案將很明顯。

不過,直到您知道,您只是瞎子,那絕不是一個好計劃。

filo
2019-10-13 15:39:09 UTC
view on stackexchange narkive permalink

沒有在AVR上運行壓縮代碼的“實用”方法,因此您的問題就變成了“如何優化固件的大小”。

工具鏈技巧(即,您不必修改代碼)

  1. 什麼是編譯器優化級別?在 gcc 中,針對最小尺寸進行優化的選項稱為 -Os

  2. 有一種稱為鏈接時間優化的功能,可以進一步優化大小。在此答案中已經提到了

  3. 鏈接器可以優化未使用的數據和符號。使用 -Wl,-gc-sections -ffunction-sections -fdata-sections

  4. 啟用
  5. 啟用 -mcall-prologues 在這裡解釋。

  6. ol>

    通用代碼技巧:

    1. 運行 nm -S --size-sort -t d your_output_file.elf 。該命令將顯示每個符號的大小(鏈接器中的符號表示數據或代碼)。然後,您可以找到最大的優化機會。

    2. 嘗試查找可以單獨成為函數的代碼段。

    3. 避免使用 printf 。如果只需要將整數轉換為字符串,則 itoa 是一個選擇。您還可以簽出 xprintf,它是標準 printf 的較輕替代品。

    4. 如果您使用的是浮點數(浮點數,雙精度數),請嘗試將代碼轉換為使用整數。例如,如果您需要2個小數位,則可以使用100的簡單換算(即2.5變為250)。 AVR上的任何浮點操作(如 float x = a + b 一樣簡單)都會引入一堆庫代碼,因為CPU在硬件中不支持此類操作。

    5. ol>
sktpin
2019-10-14 19:50:09 UTC
view on stackexchange narkive permalink

如果您正在尋找減小程序代碼大小的方法-除了讓優化的編譯器&鏈接器砍掉某些功能,並且不使用標準庫功能(如其他人指出的那樣)之外,這還取決於程序代碼的組成多大。

  • 首先,嘗試找到一種方法來向您展示程序中哪些部分最涉及到大小。 las,我對AVR Studio不熟悉,但是在這裡,用戶不滿意,文章#7列出了單個目標文件的大小。如果您的程序有多個模塊,那麼您至少會知道其中哪些模塊最大,並且是手動優化的良好候選者。
    • 為什麼要手動重構代碼?如果您可以通過這種方式使代碼更小,而不是使用編譯器的優化方法,則調試(例如使用GDB等逐步執行代碼)將比優化器在實際執行的代碼和實際執行的代碼之間形成明顯差異時更好。您的源代碼,使事情變得不那麼容易
  • 這裡有一些提示:請參閱“減少代碼大小的3條提示和技巧”一章
  • 避免“複製&粘貼”代碼
    • 即使用例程在多個位置執行一系列需要執行的操作,然後從這些位置調用
    • 這聽起來似乎很明顯(“我已經使用過函數,du!”),但是值得在代碼中尋找幾乎完全相同的地方,每次都要執行幾個步驟,而所有不同之處僅取決於幾個可能是函數參數的參數
    • 旁注:還有其他原因可以這樣做:常規使用例程
  • (更加絕望,爭取幾個額外的字節...)考慮將較大的switch / case或if..else..if..else ...塊(從中調用函數)轉換為具有以下內容的const數組:函數指針。僅當所有函數具有相同的簽名(即相同的指針類型)並且根據該值計算數組索引來確定調用的內容本身並不會增加很多代碼時,該函數才有效。為數組建立索引並調用函數指針所產生的代碼可能比在相同情況下的大量切換/大小寫或if / else編寫的代碼小。(對我來說確實有用-不過是在32位Microblaze上。YMMV)
Dvidunis
2019-10-13 02:34:56 UTC
view on stackexchange narkive permalink

如果您的項目由多個源文件組成(就像大多數項目一樣),您還可以查看Link Time Optimization(通常縮寫為LTO)。

它在對象之間進行了額外的優化(顧名思義,是在鏈接時)。

您可能會在IDE中尋找特定的“鏈接時間優化” /“ LTO”選項,或者尋找添加編譯器標誌的地方。

如果編譯器是基於GCC或Clang的,則可以在編譯和鏈接時間期間添加 -flto 標誌(如果相關,請同時包括CFLAGS和LDFLAGS)。

這可以優化未調用的整個代碼塊(內部函數),或針對特定的輸入模式進行優化。

請注意,如果您使用標準庫,則需要確保使用LTO進行編譯以節省大量資金。

您可以在此處閱讀有關LTO的更多信息: https://en.wikipedia.org/wiki/Interprocedural_optimization
還有一個來自Linux內核的示例: https://lwn.net/Articles/744507/



該問答將自動從英語翻譯而來。原始內容可在stackexchange上找到,我們感謝它分發的cc by-sa 4.0許可。
Loading...