本應(yīng)用筆記討論了MAX-IDE為MAXQ?微控制器上的應(yīng)用編程提供的代碼和數(shù)據(jù)段工具。代碼和數(shù)據(jù)段機(jī)制提供了一種在數(shù)據(jù)存儲(chǔ)器中自動(dòng)聲明變量位置并使用起始值初始化這些變量的方法。然后,可以使用應(yīng)用程序代碼將這些變量值緩存在閃存中,并根據(jù)需要還原它們。這種方法允許基于匯編的應(yīng)用利用MAX-IDE提供的數(shù)據(jù)段自動(dòng)加載,同時(shí)無(wú)論微控制器是否連接到JTAG調(diào)試器,都能始終如一地運(yùn)行。MAXQ2000微控制器評(píng)估板用于演示方法,文中提供了代碼示例。
概述
MAXQ匯編應(yīng)用中的變量可以存儲(chǔ)在工作寄存器(如累加器A[0]至A[15])或數(shù)據(jù)存儲(chǔ)器(SRAM)中。將變量存儲(chǔ)在數(shù)據(jù)存儲(chǔ)器中為應(yīng)用程序變量提供了更大的工作區(qū)域,但確實(shí)需要額外的訪問(wèn)時(shí)間。
MaxQAsm 匯編器和 MAX-IDE 環(huán)境提供了一種聲明單獨(dú)代碼和數(shù)據(jù)段的機(jī)制,并為每個(gè)段生成單獨(dú)的十六進(jìn)制輸出文件。在運(yùn)行時(shí),MAX-IDE自動(dòng)將數(shù)據(jù)段文件加載到程序存儲(chǔ)器(通常為閃存)中,將數(shù)據(jù)段文件加載到數(shù)據(jù)存儲(chǔ)器(通常為RAM)中。但是,由于數(shù)據(jù)存儲(chǔ)器是易失性的,一旦微控制器斷電,數(shù)據(jù)段內(nèi)容將不會(huì)保持不變。
本應(yīng)用筆記首先使用MAXQ2000評(píng)估(評(píng)估)板演示如何在初始應(yīng)用運(yùn)行期間將這些預(yù)加載的數(shù)據(jù)存儲(chǔ)器值保存在閃存中,然后在微控制器隨后再次上電時(shí)如何刷新閃存中的數(shù)據(jù)段值。這個(gè)兩步過(guò)程允許使用相同的數(shù)據(jù)段機(jī)制來(lái)聲明和初始化變量,無(wú)論應(yīng)用程序是在開(kāi)發(fā)中(連接到JTAG適配器和MAX-IDE)還是在現(xiàn)場(chǎng)運(yùn)行。
本應(yīng)用筆記的演示代碼為MAXQ2000微控制器和MAXQ2000評(píng)估板編寫,但所示代碼和原理適用于任何具有可重寫程序閃存的MAXQ20微控制器。
MAX-IDE環(huán)境的最新安裝包和文檔可免費(fèi)下載。
最大集成開(kāi)發(fā)臺(tái)安裝
MAXQ磁芯組裝指南
開(kāi)發(fā)工具指南
變量和存儲(chǔ)位置
嵌入式應(yīng)用程序通常需要一定的工作空間來(lái)存儲(chǔ)狀態(tài)信息、配置設(shè)置、中間工作值、循環(huán)計(jì)數(shù)器和計(jì)算結(jié)果。存儲(chǔ)在此工作空間中的值通常稱為變量,并具有以下特征。
它們是暫時(shí)的。如果應(yīng)用程序因電源故障或重置而中斷,則不需要保存它們。
它們經(jīng)常被訪問(wèn)和更新。它們必須存儲(chǔ)在可以快速讀取或?qū)懭氲奈恢?位置的寫入次數(shù)不得有限制。
它們通常具有定義的初始值。用戶的代碼必須在應(yīng)用程序開(kāi)始時(shí)將它們?cè)O(shè)置為特定值。
在用 C 或其他高級(jí)語(yǔ)言編寫并編譯為匯編代碼的應(yīng)用程序中,編譯器通常自動(dòng)處理變量的空間分配(以及將變量初始化為預(yù)定義起始值的過(guò)程)。在這種情況下,用戶只需要聲明變量、其類型和(可選)其初始值。編譯器處理其余部分。
unsigned int c = 0x1234;
但是,當(dāng)直接用MAXQ匯編語(yǔ)言編寫應(yīng)用程序時(shí),必須明確地為變量分配空間并將變量設(shè)置為初始值。這種詳細(xì)的操作允許對(duì)MAXQ微控制器上的可用資源進(jìn)行更嚴(yán)格的控制,但增加了系統(tǒng)的復(fù)雜性。
對(duì)于基于程序集的小型應(yīng)用程序或不需要大量工作空間的應(yīng)用程序,可以使用內(nèi)部寄存器來(lái)存儲(chǔ)所有應(yīng)用程序變量。此方法具有兩個(gè)重要優(yōu)勢(shì):
緊湊、快速的代碼。寄存器變量可以在短短一個(gè)指令周期內(nèi)從另一個(gè)寄存器變量讀取、寫入或復(fù)制到另一個(gè)寄存器變量,具體取決于寄存器的位置。在基于MAXQ20的微控制器上,在最壞的情況下,通常不需要超過(guò)兩個(gè)指令周期。
對(duì)變量的直接操作。一些內(nèi)部寄存器位置可以直接操作。例如,可以選擇 16 個(gè)工作累加器 A[0] 到 A[15] 中的任何一個(gè)(使用 AP 寄存器)作為活動(dòng)累加器 Acc。這意味著,如果需要對(duì)存儲(chǔ)在其中一個(gè)寄存器中的變量執(zhí)行操作,則可以直接在該寄存器上執(zhí)行該操作,而無(wú)需復(fù)制值、執(zhí)行操作并重新復(fù)制值。類似地,存儲(chǔ)在 LC[0] 和 LC[1] 寄存器中的變量可以通過(guò)執(zhí)行 djnz 指令直接用作循環(huán)計(jì)數(shù)器。
較大的應(yīng)用或需要大量工作變量的應(yīng)用可以受益于將其部分或全部變量存儲(chǔ)在基于SRAM的數(shù)據(jù)存儲(chǔ)器中。此方法允許創(chuàng)建更多數(shù)量的變量,直至達(dá)到數(shù)據(jù)存儲(chǔ)器大小的限制。以這種方式存儲(chǔ)的變量可以使用MAXQ20內(nèi)核的標(biāo)準(zhǔn)數(shù)據(jù)指針訪問(wèn),該指針可用于讀寫字節(jié)大小或字大小的變量。(注:本應(yīng)用筆記中的所有代碼示例都假定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
如果必須對(duì)變量執(zhí)行一長(zhǎng)串計(jì)算,則可以將該變量的值復(fù)制到工作寄存器中,如上面的示例代碼所示。所有中間操作都可以使用該工作寄存器執(zhí)行,并且一旦計(jì)算完成,該值就可以復(fù)制回變量。
MAX-IDE 中的段聲明
一旦決定將應(yīng)用變量存儲(chǔ)在基于SRAM的數(shù)據(jù)存儲(chǔ)器中,如何確定變量的存儲(chǔ)位置?
通常,所有數(shù)據(jù)存儲(chǔ)器都可供應(yīng)用程序使用,但調(diào)試器使用的存儲(chǔ)器中最高的 32 字節(jié)除外。這意味著聲明變量只是在數(shù)據(jù)存儲(chǔ)器中為其定義位置的問(wèn)題。然后,每當(dāng)讀取或?qū)懭胱兞繒r(shí),代碼都會(huì)使用此位置。#define宏可用于將變量位置與符號(hào)名稱相關(guān)聯(lián)。
#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
這種方法效果很好,但它有幾個(gè)問(wèn)題。
每個(gè)變量的位置必須提前確定。此任務(wù)可能非常耗時(shí),特別是如果以后決定將所有變量移動(dòng)到數(shù)據(jù)存儲(chǔ)器的不同區(qū)域。
必須注意不要意外地對(duì)多個(gè)變量使用相同的位置。如果犯了這個(gè)錯(cuò)誤,可能很難跟蹤錯(cuò)誤。
變量的任何初始(起始)值都必須由應(yīng)用程序代碼顯式加載,如上面最后一行所示。如果有許多變量要以這種方式初始化,則此操作可能會(huì)占用大量代碼空間。
一種更有效的方法利用MAX-IDE的機(jī)制來(lái)聲明單獨(dú)的代碼和數(shù)據(jù)段。此方法允許應(yīng)用程序作者指定程序集代碼文件的哪些部分發(fā)往代碼空間,哪些部分發(fā)往數(shù)據(jù)空間。
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
在上述方法中,數(shù)據(jù)段中聲明的變量的地址由匯編程序自動(dòng)確定,因?yàn)樗褂门c代碼空間中的標(biāo)簽分配地址相同的方法解析文件。標(biāo)簽用于為這些變量地址分配符號(hào)名稱,dw 和 db 語(yǔ)句可用于初始化具有起始值的字大小和字節(jié)大小的變量。在這種情況下,假設(shè)在程序集文件中找不到以前的段數(shù)據(jù)指令,匯編程序?qū)牡刂?0000h 開(kāi)始數(shù)據(jù)段。這意味著 VarA 將存儲(chǔ)在字地址 0000h 處。與在代碼空間中一樣,org 語(yǔ)句可以強(qiáng)制變量位于指定地址的開(kāi)頭。
初始化數(shù)據(jù)段
在前面的代碼清單中,變量 VarA 被定義為(使用 dw 語(yǔ)句)具有 0394h 的初始值。但此值永遠(yuǎn)不會(huì)加載到代碼中的 VarA 中。那么,這個(gè)值是如何初始化的呢?答案是,數(shù)據(jù)段的初始化由MAX-IDE在項(xiàng)目編譯和執(zhí)行時(shí)自動(dòng)執(zhí)行。
MaxQAsm 匯編器通過(guò)生成輔助十六進(jìn)制輸出文件來(lái)響應(yīng)段數(shù)據(jù)指令。通常,為包含代碼數(shù)據(jù)的項(xiàng)目生成十六進(jìn)制文件。例如,如果編譯了項(xiàng)目“example.prj”,則將創(chuàng)建一個(gè)名為“example.hex”的十六進(jìn)制文件,其中包含通過(guò)組裝項(xiàng)目文件生成的代碼數(shù)據(jù)。如果定義了數(shù)據(jù)段,則將創(chuàng)建一個(gè)名為“example_d.hex”的附加十六進(jìn)制文件,其中包含在此段中組裝的數(shù)據(jù)。
執(zhí)行項(xiàng)目時(shí),MAX-IDE 會(huì)檢查在項(xiàng)目編譯期間是否生成了數(shù)據(jù)段文件(以 _d.hex 結(jié)尾)。如果存在數(shù)據(jù)段文件,MAX-IDE使用標(biāo)準(zhǔn)JTAG加載器將來(lái)自該段的數(shù)據(jù)加載到器件的數(shù)據(jù)SRAM中。這是在將標(biāo)準(zhǔn)十六進(jìn)制文件加載到程序內(nèi)存后完成的。
這種方法在開(kāi)發(fā)周期中效果很好,當(dāng)器件連接到JTAG適配器并且MAX-IDE在每個(gè)應(yīng)用程序運(yùn)行之前重新加載代碼和段數(shù)據(jù)時(shí)。但是,一旦器件斷電和通電并允許獨(dú)立運(yùn)行(未連接調(diào)試器),MAX-IDE就無(wú)法再在每次運(yùn)行前加載具有適當(dāng)值的數(shù)據(jù)段。變量將不再設(shè)置為其預(yù)期值,因此應(yīng)用程序可能無(wú)法正確執(zhí)行。這種類型的故障可能很難分析,因?yàn)橐坏┢骷匦逻B接到調(diào)試器,MAX-IDE將在每次運(yùn)行之前再次開(kāi)始加載數(shù)據(jù)段,問(wèn)題將立即消失。
保存和恢復(fù)數(shù)據(jù)段
一個(gè)問(wèn)題仍然存在:如何使應(yīng)用程序始終如一地運(yùn)行,無(wú)論是連接到調(diào)試器(每次運(yùn)行前MAX-IDE重新加載代碼和數(shù)據(jù))還是自由運(yùn)行(上電后RAM中沒(méi)有特定內(nèi)容保證)。顯而易見(jiàn)的解決方案是一個(gè)兩步過(guò)程:讓應(yīng)用程序?qū)⒆兞恐担ㄒ坏┏跏蓟┍4嬖陂W存中,并在每次復(fù)位或上電后恢復(fù)這些值。
第一步,應(yīng)用程序必須將值保存到閃存。此操作在每個(gè)主擦除和代碼加載周期之后首次執(zhí)行應(yīng)用程序時(shí)發(fā)生。
應(yīng)用程序檢查“標(biāo)志”位置,以驗(yàn)證變量之前是否未復(fù)制到閃存。此標(biāo)志可以是特殊用途的非變量位置,也可以與變量共享,只要該變量具有非零初始值(以將其與空白 RAM 位置區(qū)分開(kāi)來(lái))。
應(yīng)用程序?qū)⒚總€(gè)變量值從數(shù)據(jù)RAM復(fù)制到閃存。在大多數(shù)帶有可重寫閃存的MAXQ微控制器(如MAXQ2000)上,這是使用UROM_flashWrite功能完成的。
應(yīng)用程序在閃存中寫入一個(gè)標(biāo)志,以指示變量已存儲(chǔ)。
作為第二步,在后續(xù)運(yùn)行中,應(yīng)用程序必須將變量值從閃存還原到數(shù)據(jù)RAM中的預(yù)期位置。
應(yīng)用程序檢查閃存中的標(biāo)志位置,以驗(yàn)證變量值是否已存儲(chǔ)。
應(yīng)用程序使用 UROM_copyBuffer 例程將變量值從閃存復(fù)制到數(shù)據(jù) RAM 中的適當(dāng)位置。
下面的代碼表演示了使用MAXQ2000評(píng)估板的保存-恢復(fù)方法。在此代碼中,變量值存儲(chǔ)在地址為 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
結(jié)論
MAX-IDE提供的代碼和數(shù)據(jù)段工具提供了一種在數(shù)據(jù)存儲(chǔ)器中自動(dòng)聲明變量位置并使用起始值初始化這些變量的方法。然后,可以使用應(yīng)用程序代碼將這些變量值緩存在閃存中,并根據(jù)需要還原它們。這種方法允許基于匯編的應(yīng)用利用MAX-IDE提供的數(shù)據(jù)段自動(dòng)加載,同時(shí)無(wú)論微控制器是否連接到JTAG調(diào)試器,都能始終如一地運(yùn)行。
審核編輯:郭婷
-
微控制器
+關(guān)注
關(guān)注
48文章
7564瀏覽量
151520 -
存儲(chǔ)器
+關(guān)注
關(guān)注
38文章
7496瀏覽量
163928 -
JTAG
+關(guān)注
關(guān)注
6文章
400瀏覽量
71707
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論