轉載:F28335的位域和寄存器結構的學習

實現位域和寄存器文件結構體的具體步驟(以SCI外設爲例)

1)、定義一個寄存器文件結構體,SCI外設的寄存器在結構體中按實際的地址由低向高依次列出。

/********************************************************************

* SCI header file

* Defines a register file structure for the SCI peripheral

********************************************************************/

#define    Uint16    unsigned int

#define    Uint32    unsigned long

struct SCI_REGS {

Uint16    SCICCR_REG      SCICCR;             // Communications control register

Uint16    SCICTL1_REG     SCICTL1;             // Control register 1

Uint16                                SCIHBAUD;         // Baud rate (high) register

Uint16                                SCILBAUD;         // Baud rate (low) register

Uint16    SCICTL2_REG     SCICTL2;             // Control register 2

Uint16  SCIRXST_REG    SCIRXST;            // Receive status register

Uint16                               SCIRXEMU;               // Receive emulation buffer register

Uint16  SCIRXBUF_REG SCIRXBUF;         // Receive data buffer

Uint16                               rsvd1;                   // reserved

Uint16                               SCITXBUF;          // Transmit data buffer

Uint16  SCIFFTX_REG     SCIFFTX;            // FIFO transmit register

Uint16  SCIFFRX_REG    SCIFFRX;            // FIFO receive register

Uint16  SCIFFCT_REG     SCIFFCT;             // FIFO control register

Uint16                               rsvd2;                   // reserved

Uint16                               rsvd3;                   // reserved

Uint16  SCIPRI_REG        SCIPRI;                      // FIFO Priority control

};

2)、上面的定義本身並沒有建立任何的變量,只是定義了一個結構體,而並沒有實例化。下面即定義了具體的變量。注意在這裏使用了volatile關鍵字,它在這裏的作用很重要,這使得編譯器不會做一些錯誤的優化。

/********************************************************************

* Source file using register-file structures

* Create a variable for each of the SCI register files

********************************************************************/

volatile    struct      SCI_REGS    SciaRegs;

volatile    struct      SCI_REGS    ScibRegs;

3)、利用DATA_SECTION Pragma,將寄存器文件結構體變量分配到特殊的數據段中。如果不使用這條指令,那麼定義的寄存器文件結構體變量默認是被分配在.ebss或者.bss段的,但通過使用DATA_SECTION Pragma指令,編譯器會將其放在了一個特殊的數據段中。具體實現如下:

/********************************************************************

* Assign variables to data sections using the #pragma compiler statement

* C and C++ use different forms of the #pragma statement

* When compiling a C++ program, the compiler will define __cplusplus automatically

********************************************************************/

//----------------------------------------

#ifdef      __cplusplus

#pragma  DATA_SECTION("SciaRegsFile")

#else

#pragma  DATA_SECTION(SciaRegs,"SciaRegsFile");

#endif

volatile    struct      SCI_REGS    SciaRegs;

//----------------------------------------

#ifdef     __cplusplus

#pragma DATA_SECTION("ScibRegsFile")

#else

#pragma DATA_SECTION(ScibRegs,"ScibRegsFile");

#endif

volatile    struct      SCI_REGS    ScibRegs;

通過上面的代碼可以看到,定義的SciaRegs被分配到了SciaRegsFile段中,ScibRegs被分配到了ScibRegsFile段中。

4)、上面只是將定義的寄存器結構體變量分配到了一個特殊的數據段中,通過cmd文件,可將其映射到實際的存儲單元,進而和外設實際的存儲器映射地址統一起來。實現如下:

/********************************************************************

* Memory linker .cmd file

* Assign the SCI register-file structures to the corresponding memory

********************************************************************/

MEMORY

{

...

PAGE 1:

SCIA : origin = 0x007050, length = 0x000010 /* SCI-A registers */

SCIB : origin = 0x007750, length = 0x000010 /* SCI-B registers */

...

}

SECTIONS

{

...

SciaRegsFile : > SCIA, PAGE = 1

ScibRegsFile : > SCIB, PAGE = 1

...

}

5)、添加位域定義。

獲取寄存器中特定的位經常是很有用的,位域的定義就提供了這種方便性;但是與此同時位域也缺乏硬件平臺之間的可移植性。在位域的定義中,最低位,也就是0位,是寄存器中的第一個位域;位域不能超過寄存器的位數,最多爲16位。

/********************************************************************

* SCI header file

********************************************************************/

//----------------------------------------------------------

// SCICCR communication control register bit definitions:

//

struct      SCICCR_BITS {                 // bit deion

Uint16    SCICHAR:3;                       // 2:0 Character length control

Uint16    ADDRIDLE_MODE:1;        // 3 ADDR/IDLE Mode control

Uint16    LOOPBKENA:1;                 // 4 Loop Back enable

Uint16    PARITYENA:1;                  // 5 Parity enable

Uint16    PARITY:1;                         // 6 Even or Odd Parity

Uint16    STOPBITS:1;                      // 7 Number of Stop Bits

Uint16    rsvd1:8;                              // 15:8 reserved

};

//-------------------------------------------

// SCICTL1 control register 1 bit definitions:

//

struct SCICTL1_BITS {                            // bit deion

Uint16    RXENA:1;                          // 0 SCI receiver enable

Uint16    TXENA:1;                          // 1 SCI transmitter enable

Uint16    SLEEP:1;                           // 2 SCI sleep

Uint16    TXWAKE:1;                       // 3 Transmitter wakeup method

Uint16    rsvd:1;                                // 4 reserved

Uint16    SWRESET:1;                      // 5 Software reset

Uint16    RXERRINTENA:1;             // 6 Receive interrupt enable

Uint16    rsvd1:9;                              // 15:7 reserved

};

在上面的定義中,使用了操作符“:”,用來說明位域的長度,即當前位域佔幾位。

6)、使用聯合體。除了能夠方便的訪問位域外,有時候也希望能夠對寄存器整體訪問,使用聯合體能夠實現這種操作。

/********************************************************************

* SCI header file

********************************************************************/

union SCICCR_REG {

Uint16                                all;

struct      SCICCR_BITS      bit;

};

union SCICTL1_REG {

Uint16                                all;

struct      SCICTL1_BITS     bit;

};

7)、將添加位域後的寄存器結構體重新實現。

/********************************************************************

* SCI header file

* Defines a register file structure for the SCI peripheral

********************************************************************/

#define    Uint16    unsigned int

#define    Uint32    unsigned long

struct SCI_REGS {

Uint16    SCICCR_REG      SCICCR;             // Communications control register

Uint16    SCICTL1_REG     SCICTL1;             // Control register 1

Uint16                                SCIHBAUD;         // Baud rate (high) register

Uint16                                SCILBAUD;         // Baud rate (low) register

Uint16    SCICTL2_REG     SCICTL2;             // Control register 2

Uint16  SCIRXST_REG    SCIRXST;            // Receive status register

Uint16                               SCIRXEMU;               // Receive emulation buffer register

Uint16  SCIRXBUF_REG SCIRXBUF;         // Receive data buffer

Uint16                               rsvd1;                   // reserved

Uint16                               SCITXBUF;          // Transmit data buffer

Uint16  SCIFFTX_REG     SCIFFTX;            // FIFO transmit register

Uint16  SCIFFRX_REG    SCIFFRX;            // FIFO receive register

Uint16  SCIFFCT_REG     SCIFFCT;             // FIFO control register

Uint16                               rsvd2;                   // reserved

Uint16                               rsvd3;                   // reserved

Uint16  SCIPRI_REG        SCIPRI;                      // FIFO Priority control

};

 

 

進行“讀-修改-寫”操作時需要注意的寄存器,及其解決方案

1、在“讀-修改-寫”操作時,硬件可能修改的寄存器。

(1)在需要清除PIEIFRx某個位的值的時候,需要藉助CPU的中斷來清除。這時將修改中斷向量表,將對應的中斷重新分配到一個假的ISR中,然後讓CPU進入這個假的ISR,自動清除相應的位,然後再恢復中斷向量表。

(2)當對GPxDAT進行操作時,由於GPxDAT反映的是引腳上的值,在對其連續“讀-修改-寫”操作時,由於讀和寫操作的時間不同,會得到不希望的結果。解決措施是:不通過GPxDAT改變引腳的值,而使用其他寄存器GPxSET/GPxCLEAR/GPxTOGGLE,由於這些寄存器只對具體的位操作,因而不會影響到其他的位。

2、具有寫1清除位的寄存器。

例如TCR寄存器中的TIF位,當向其中寫1的時候回將其清零。在讀取它的值之前如果先要停止寄存器,就要對TSS位操作,這時就會發生一次“讀-修改-寫”操作。如果此時TIF爲1,經過這個操作後就會被清零,所以後面的質量永遠也檢測到TIF爲1。比如下面的例子:

// Stop the CPU-Timer

CpuTimer0Regs.TCR.bit.TSS = 1;              3F80C7 MOVW DP,#0x0030

3F80C9 OR         @4,#0x0010

// Check to see if TIF is set                        3F80CB TBIT      @4,#15

if (CpuTimer0Regs.TCR.bit.TIF == 1)        3F80CC SBF       L1,NTC

{                                                             3F80CD        NOP

// TIF set, insert action here                       3F80CE L1:

// NOP is only a place holder ....

asm(" NOP");

}

解決的方法是使用一個虛擬的寄存器,在停止定時器時,對TIF位寫0,這樣就不會改變TIF的值了。示例代碼如下:

union TCR_REG shadowTCR;

// Use a shadow register to stop the timer

// and preserve TIF (write 1-to-clear bit)

shadowTCR.all = CpuTimer0Regs.TCR.all;               3F80C7 MOVW DP,#0x0030

shadowTCR.bit.TSS = 1;                                         3F80C9 MOV     AL,@4

shadowTCR.bit.TIF = 0;                                          3F80CA        ORB      AL,#0x10

CpuTimer0Regs.TCR.all = shadowTCR.all;               3F80CB MOVL   XAR5,#0x000C00

3F80CD        AND      AL,@AL,#0x7FFF

// Check the TIF flag                                               3F80CF MOV     *+XAR5[4],AL

if(CpuTimer0Regs.TCR.bit.TIF == 1)                       3F80D0 TBIT      *+XAR5[4],#15

{                                                                           3F80D1 SBF       L1,NTC

// TIF set, insert action here                                     3F80D2 NOP

// NOP is only a place holder                                   3F80D3 L1:

asm(" NOP");

}

3、需要特定值的寄存器。

在向WDCHK中的檢查位寫數的時候必須始終爲1,0,1;否則就會被認爲是不合法的,將復位器件。但是在讀取的時候這幾位始終爲0,0,0;如果將這個值寫回,那麼就會造成器件的復位。解決方法是:在頭文件中,不對WDCHK定義位域操作,這樣就避免了對WDCHK的“讀-修改-寫”操作,在對其操作時只有一個固定的寫操作。示例代碼如下:

SysCtrlRegs.WDCR = 0x0068;

 

對F28335的程序來講,它充分利用了位域和寄存器文件結構體,通過這種結構將衆多的外設組織起來了,甚至中斷向量表也是通過這種結構來實現的。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章