本應用筆記討論了MAX-IDE為MAXQ?微控制器上的應用編程提供的代碼和數據段工具。代碼和數據段機制提供了一種在數據存儲器中自動聲明變量位置并使用起始值初始化這些變量的方法。然后,可以使用應用程序代碼將這些變量值緩存在閃存中,并根據需要還原它們。這種方法允許基于匯編的應用利用MAX-IDE提供的數據段自動加載,同時無論微控制器是否連接到JTAG調試器,都能始終如一地運行。MAXQ2000微控制器評估板用于演示方法,文中提供了代碼示例。
概述
MAXQ匯編應用中的變量可以存儲在工作寄存器(如累加器A[0]至A[15])或數據存儲器(SRAM)中。將變量存儲在數據存儲器中為應用程序變量提供了更大的工作區域,但確實需要額外的訪問時間。
MaxQAsm 匯編器和 MAX-IDE 環境提供了一種聲明單獨代碼和數據段的機制,并為每個段生成單獨的十六進制輸出文件。在運行時,MAX-IDE自動將數據段文件加載到程序存儲器(通常為閃存)中,將數據段文件加載到數據存儲器(通常為RAM)中。但是,由于數據存儲器是易失性的,一旦微控制器斷電,數據段內容將不會保持不變。
本應用筆記首先使用MAXQ2000評估(評估)板演示如何在初始應用運行期間將這些預加載的數據存儲器值保存在閃存中,然后在微控制器隨后再次上電時如何刷新閃存中的數據段值。這個兩步過程允許使用相同的數據段機制來聲明和初始化變量,無論應用程序是在開發中(連接到JTAG適配器和MAX-IDE)還是在現場運行。
本應用筆記的演示代碼為MAXQ2000微控制器和MAXQ2000評估板編寫,但所示代碼和原理適用于任何具有可重寫程序閃存的MAXQ20微控制器。
最大集成開發臺安裝
MAXQ磁芯組裝指南
開發工具指南
變量和存儲位置
嵌入式應用程序通常需要一定的工作空間來存儲狀態信息、配置設置、中間工作值、循環計數器和計算結果。存儲在此工作空間中的值通常稱為變量,并具有以下特征。
它們是暫時的。如果應用程序因電源故障或重置而中斷,則不需要保存它們。
它們經常被訪問和更新。它們必須存儲在可以快速讀取或寫入的位置;位置的寫入次數不得有限制。
它們通常具有定義的初始值。用戶的代碼必須在應用程序開始時將它們設置為特定值。
在用 C 或其他高級語言編寫并編譯為匯編代碼的應用程序中,編譯器通常自動處理變量的空間分配(以及將變量初始化為預定義起始值的過程)。在這種情況下,用戶只需要聲明變量、其類型和(可選)其初始值。編譯器處理其余部分。
unsigned int c = 0x1234;
但是,當直接用MAXQ匯編語言編寫應用程序時,必須明確地為變量分配空間并將變量設置為初始值。這種詳細的操作允許對MAXQ微控制器上的可用資源進行更嚴格的控制,但增加了系統的復雜性。
對于基于程序集的小型應用程序或不需要大量工作空間的應用程序,可以使用內部寄存器來存儲所有應用程序變量。此方法具有兩個重要優勢:
緊湊、快速的代碼。寄存器變量可以在短短一個指令周期內從另一個寄存器變量讀取、寫入或復制到另一個寄存器變量,具體取決于寄存器的位置。在基于MAXQ20的微控制器上,在最壞的情況下,通常不需要超過兩個指令周期。
對變量的直接操作。一些內部寄存器位置可以直接操作。例如,可以選擇 16 個工作累加器 A[0] 到 A[15] 中的任何一個(使用 AP 寄存器)作為活動累加器 Acc。這意味著,如果需要對存儲在其中一個寄存器中的變量執行操作,則可以直接在該寄存器上執行該操作,而無需復制值、執行操作并重新復制值。類似地,存儲在 LC[0] 和 LC[1] 寄存器中的變量可以通過執行 djnz 指令直接用作循環計數器。
較大的應用或需要大量工作變量的應用可以受益于將其部分或全部變量存儲在基于SRAM的數據存儲器中。此方法允許創建更多數量的變量,直至達到數據存儲器大小的限制。以這種方式存儲的變量可以使用MAXQ20內核的標準數據指針訪問,該指針可用于讀寫字節大小或字大小的變量。(注:本應用筆記中的所有代碼示例都假定DP[0]配置為在word模式下工作。
move DP[0], #0010h ; Location of variable in data memory move Acc, @DP[0] ; Read variable add #1 ; Increment variable value by 1 move @DP[0], Acc ; Store variable back in data memory
如果必須對變量執行一長串計算,則可以將該變量的值復制到工作寄存器中,如上面的示例代碼所示。所有中間操作都可以使用該工作寄存器執行,并且一旦計算完成,該值就可以復制回變量。
MAX-IDE 中的段聲明
一旦決定將應用變量存儲在基于SRAM的數據存儲器中,如何確定變量的存儲位置?
通常,所有數據存儲器都可供應用程序使用,但調試器使用的存儲器中最高的 32 字節除外。這意味著聲明變量只是在數據存儲器中為其定義位置的問題。然后,每當讀取或寫入變量時,代碼都會使用此位置。#define宏可用于將變量位置與符號名稱相關聯。
#define VarA #0020h #define VarB #0021h #define VarC #0022h move DP[0], VarA ; Point to VarA variable move Acc, @DP[0] ; Read value of variable move DP[0], VarB ; Point to VarB variable move @DP[0], Acc ; Copy VarA to VarB move DP[0], VarC ; Point to VarC variable move @DP[0], #1234h ; Set VarC = 1234h
這種方法效果很好,但它有幾個問題。
每個變量的位置必須提前確定。此任務可能非常耗時,特別是如果以后決定將所有變量移動到數據存儲器的不同區域。
必須注意不要意外地對多個變量使用相同的位置。如果犯了這個錯誤,可能很難跟蹤錯誤。
變量的任何初始(起始)值都必須由應用程序代碼顯式加載,如上面最后一行所示。如果有許多變量要以這種方式初始化,則此操作可能會占用大量代碼空間。
一種更有效的方法利用MAX-IDE的機制來聲明單獨的代碼和數據段。此方法允許應用程序作者指定程序集代碼文件的哪些部分發往代碼空間,哪些部分發往數據空間。
segment code move DP[0], #VarA ; Point to VarA move Acc, @DP[0] ; Get current value of VarA add #1 ; Increment it move @DP[0], Acc ; Store value back in VarA segment data VarA: dw 0394h ; Initial value for VarA
在上述方法中,數據段中聲明的變量的地址由匯編程序自動確定,因為它使用與代碼空間中的標簽分配地址相同的方法解析文件。標簽用于為這些變量地址分配符號名稱,dw 和 db 語句可用于初始化具有起始值的字大小和字節大小的變量。在這種情況下,假設在程序集文件中找不到以前的段數據指令,匯編程序將從地址 0000h 開始數據段。這意味著 VarA 將存儲在字地址 0000h 處。與在代碼空間中一樣,org 語句可以強制變量位于指定地址的開頭。
初始化數據段
在前面的代碼清單中,變量 VarA 被定義為(使用 dw 語句)具有 0394h 的初始值。但此值永遠不會加載到代碼中的 VarA 中。那么,這個值是如何初始化的呢?答案是,數據段的初始化由MAX-IDE在項目編譯和執行時自動執行。
MaxQAsm 匯編器通過生成輔助十六進制輸出文件來響應段數據指令。通常,為包含代碼數據的項目生成十六進制文件。例如,如果編譯了項目“example.prj”,則將創建一個名為“example.hex”的十六進制文件,其中包含通過組裝項目文件生成的代碼數據。如果定義了數據段,則將創建一個名為“example_d.hex”的附加十六進制文件,其中包含在此段中組裝的數據。
執行項目時,MAX-IDE 會檢查在項目編譯期間是否生成了數據段文件(以 _d.hex 結尾)。如果存在數據段文件,MAX-IDE使用標準JTAG加載器將來自該段的數據加載到器件的數據SRAM中。這是在將標準十六進制文件加載到程序內存后完成的。
這種方法在開發周期中效果很好,當器件連接到JTAG適配器并且MAX-IDE在每個應用程序運行之前重新加載代碼和段數據時。但是,一旦器件斷電和通電并允許獨立運行(未連接調試器),MAX-IDE就無法再在每次運行前加載具有適當值的數據段。變量將不再設置為其預期值,因此應用程序可能無法正確執行。這種類型的故障可能很難分析,因為一旦器件重新連接到調試器,MAX-IDE將在每次運行之前再次開始加載數據段,問題將立即消失。
保存和恢復數據段
一個問題仍然存在:如何使應用程序始終如一地運行,無論是連接到調試器(每次運行前MAX-IDE重新加載代碼和數據)還是自由運行(上電后RAM中沒有特定內容保證)。顯而易見的解決方案是一個兩步過程:讓應用程序將變量值(一旦初始化)保存在閃存中,并在每次復位或上電后恢復這些值。
第一步,應用程序必須將值保存到閃存。此操作在每個主擦除和代碼加載周期之后首次執行應用程序時發生。
應用程序檢查“標志”位置,以驗證變量之前是否未復制到閃存。此標志可以是特殊用途的非變量位置,也可以與變量共享,只要該變量具有非零初始值(以將其與空白 RAM 位置區分開來)。
應用程序將每個變量值從數據RAM復制到閃存。在大多數帶有可重寫閃存的MAXQ微控制器(如MAXQ2000)上,這是使用UROM_flashWrite功能完成的。
應用程序在閃存中寫入一個標志,以指示變量已存儲。
作為第二步,在后續運行中,應用程序必須將變量值從閃存還原到數據RAM中的預期位置。
應用程序檢查閃存中的標志位置,以驗證變量值是否已存儲。
應用程序使用 UROM_copyBuffer 例程將變量值從閃存復制到數據 RAM 中的適當位置。
下面的代碼表演示了使用MAXQ2000評估板的保存-恢復方法。在此代碼中,變量值存儲在地址為 7000h–71FFh 的閃存中。
$include(maxQ2000.inc) ;; Code memory (flash) : 0000h-7FFFh (word addr) ;; Data memory (RAM) : 0000h-03FFh (word addr) org 0000h ljump start ; Skip over password area org 0020h start: move DPC, #1Ch ; Set all pointers to word mode move DP[0], #0F000h ; Check first variable value (flag) lcall UROM_moveDP0 ; 'move GR, @DP[0]' executed by Utility ROM move Acc, GR cmp #1234h jump NE, copyToFlash ;; This is the "free-running" code, executed on subsequent power-ups, that copies ;; values from the flash back into their proper data segment locations. move DP[0], #0F000h ; Source: Flash location 7000h move BP, #0 ; Dest: Start of RAM move Offs, #0 move LC[0], #100h ; Copy 256 words lcall UROM_copyBuffer jump main ;; This is the first-pass code. A bit of a trick here; because MAX-IDE enters ;; and exits the loader separately when loading the code and data segment files, ;; the application is allowed to execute briefly before the data segment file ;; has been loaded. The first four lines under copyFlash ensure that the ;; application waits for MAX-IDE to load the data segment file before continuing. copyToFlash: move DP[0], #0h ; Wait for flag variable to be loaded by MAX-IDE. move Acc, @DP[0] ; Note that this will reset the application; the cmp #1234h ; data segment is not loaded while the application jump NE, copyToFlash ; is still running. move DP[0], #0 ; Start of RAM variable area move A[4], #7000h ; Location in flash to write to move LC[0], #100h ; Store 256 words in flash 7000h-70FFh copyToFlash_loop: move DP[0], DP[0] ; Refresh the data pointer to read values correctly, ; because calling UROM_flashWrite changes memory ; contexts and affects the cached @DP[0] value move A[0], A[4] ; Location to write move A[1], @DP[0]++ ; Value to write (taken from RAM) lcall UROM_flashWrite move Acc, A[4] add #1 move A[4], Acc djnz LC[0], copyToFlash_loop main: move PD0, #0FFh ; Set all port 0 pins to output move PO0, #000h ; Drive all port 0 pins low (LEDs off) move DPC, #1Ch ; Set pointers to word mode move DP[0], #varA move Acc, @DP[0] cmp #1234h ; Verify that the variable is set correctly jump NE, fail pass: move PO0, #55h sjump $ fail: sjump $ segment data org 0000h varA: dw 1234h org 00FFh varB: dw 5678h end
結論
MAX-IDE提供的代碼和數據段工具提供了一種在數據存儲器中自動聲明變量位置并使用起始值初始化這些變量的方法。然后,可以使用應用程序代碼將這些變量值緩存在閃存中,并根據需要還原它們。這種方法允許基于匯編的應用利用MAX-IDE提供的數據段自動加載,同時無論微控制器是否連接到JTAG調試器,都能始終如一地運行。
審核編輯:郭婷
-
微控制器
+關注
關注
48文章
7487瀏覽量
151045 -
存儲器
+關注
關注
38文章
7452瀏覽量
163599 -
JTAG
+關注
關注
6文章
398瀏覽量
71597
發布評論請先 登錄
相關推薦
評論