外部資料結構


在寫 CPU 或介面晶片的驅動程式時, 經常會使用到某些固定位址, 如: ARM Cortex-M 把系統設定及狀態對應到記憶體的特定位址, 某些周邊 IC, 例如 PCI, USB... 也是使用一小段記憶體空間. (註: 常見的周邊 IC 暫存器定址有二種: 一種是只有二個位址空間, 一個是 '指令/地址暫存器', 一個是 '資料暫存器'; 另一種則是直接使用 CPU 的記憶體空間來對應)

軟體功力較佳的 SoC 晶片製造廠所提供的驅動程式, 通常會將這一小段記憶體空間以結構 (struct) 的方式定義好, 再使用 define 將特定的位址值 (常數), 定義成一虛擬變數. 當然如果晶片功能比較簡單就不見得是用這種方法.

// Define Hardware register structures
// Key word 'volatile' is necessary for not to cache value in CPU registers
typedef struct {
volatile unsigned long DATA;		// BASE+0x00
volatile unsigned long DSR;			//      0x04
         unsigned long RESERVED[4];	//      0x08~0x14
volatile unsigned long FLAG;		//      0x18
...
} CHIP_t;

// Define virtual pointers point to every hardware unit
#define pCHIP_unit0 ((CHIP_t *) 0x40003000)
#define pCHIP_unit1 ((CHIP_t *) 0x40004000)
#define pCHIP_unit2 ((CHIP_t *) 0x40005000)
...
// Codes that reference the hardware
pCHIP_unit0->DSR = 0xA0;		// 0x40003004
pCHIP_unit1->DATA = value;		// 0x40004000

上例是使用 '結構指標' 型式的表示方法 (->) 來存取結構元素, 當然我們也可以直接使用 '結構變數' 型式的表示方法 (.) 來存取結構元素.

// Define virtual variable for every hardware unit
#define CHIP_unit0 (*(CHIP_t *) 0x40003000)
#define CHIP_unit1 (*(CHIP_t *) 0x40004000)
#define CHIP_unit2 (*(CHIP_t *) 0x40005000)
...
// Codes that reference the hardware
CHIP_unit0.DSR = 0xA0;			// 0x40003004
CHIP_unit1.DATA = value;		// 0x40004000

要注意的是這二種寫法編輯出來的 obj. code 應該要一模一樣的 (因為 conpiler 知道: 變數的地址是一個常數). 應用上完全取決於實際的需求, 或者你習慣看哪一種型式.

外部函數


位於外部的特定位址的函數宣告法如下:

/* Define virtual function (external function)
 * at specified address
 */
#define FLASH_WRITE(a,b,c)  \
    ((uint8_t (*)(void *, void *, uint16_t))0x003F00)(a, b, c)

置換說明:

FLASH_WRITE 被換成了常數(特定位址) 0x003F00, 同時這個常數被 (uint8_t (*)(void*, void*, uint16_t)) 作了型別轉換 (type casting), 其中:

  • (*)(...) 是把常數(特定位址)轉型為函數的位址
  • uint8_t 是此函數的回傳值型別
  • (void *, void *, uint16_t) 是後面的函數參數 (a, b, c) 各自的型別 (依序一個對應一個), 用來作為型別檢查
  • 最後面的 (a, b, c) 和前面 FLASH_WRITE 的參數位置保持一致, 所以呼叫函數時的參數傳遞也保持一致

Type Cast to Func Pointer

例二: (上例轉成 Keil C51)

/* Define virtual function (external function)
 * at specified address
 */
#define FLASH_WRITE(a,b,c)  \
    ((U8_T (CODE *)(void XDATA *, void CODE *, U16_T))0x003F00)(a, b, c)


參考資料: function pointer

#include <stdio.h>

void my_int_func(int x)
{
    printf( "%d\n", x );
}

int main()
{
    void (*foo)(int);
    /* the ampersand is actually optional */
    foo = &my_int_func;

    return 0;
}


相關文章:

    MagicJackTing 發表在 痞客邦 留言(0) 人氣()