Nios ii設備管理分析

admin @ 2014-03-26 , reply:0

Nios II設備分析
       Altera公司是世界上可編程晶元系統(SOPC)解決方案領先者之一,Nios II是Altera公司推出的最新32位嵌入式軟核處理器,具有很大的靈活性,Nios II開發包中含有一套通用外設和介面庫,用戶可以方便的進行系統集成。我們也需要將擁有自主知識產權的IP集成到Nios II處理器系統,通過SOPC Builder軟體的用戶邏輯介面嚮導可以方便的將IP集成到Nios II處理器系統中,同時提供設備驅動程序,本文對Nios II設備體系做一個分析,供開發人員在編寫設備驅動程序時參考。

Nios設備體系總體說明
      Nios II與以往版本Nios的設備體系有了較大的改進,Nios II不再使用SDK方式提供設備驅動,而是採用了硬體抽象庫(hardware abstraction layer system library, HAL),應用程序不再直接去控制硬體設備,而是調用HAL API去驅動。HAL API包含了ANSI C 標準庫,應用開發人員可以用熟悉的C庫函數存取(控制)設備和文件,HAL使Nios II中的設備象UNIX系統設備一樣具有相對一致的開發介面,同時也提供了UNIX風格的庫函數,其使用方式和習慣類似於我們熟悉的UNIX (LINUX)系統,設備使用更加一致。這種體系使應用開發人員和設備驅動開發人員可以分工合作,提高開發效率,同時降低應用開發難度。下面是基於HAL 系統邏輯層次圖:
 

Nios II 設備與硬體系統定義的相關性
       Nios II系統開發是一個用戶可定製的高度靈活的過程,在SOPC Builder中用戶定義處理器系統和外設生成相關的.ptf文件,Nios II IDE 根據此ptf文件在創建項目時為項目生成系統庫,其中system.h完整的定義硬體系統參數, alt_sys_init.c完成外設系統資源的分配和設備環境的初始化,這兩個文件是我們分析的入口,如圖:

 
Nios II項目邏輯結構示意圖如下:

 

外設系統資源的分配和設備環境的初始化
        Nios II系統中設備驅動程序、實時操作系統(ucos II)和應用程序最終被編譯為同一個二進位文件,下載到目標系統FLASH中使用。所以設備資源都以全局變數的形式定義,相同種類的設備加入設備雙向鏈表中,通過HAL API使用設備。下面以lan91c111網路外設為例說明外設系統資源的分配和設備環境的初始化。

1. 全局設備鏈表的定義

在系統庫alt_lwip_dev.c中通過宏ALT_LLIST_HEAD(alt_lwip_device_list)定義了alt_lwip_device_list的設備雙向鏈表。

在alt_llist.h中宏ALT_LLIST_HEAD相關定義如下:

typedef struct alt_llist_s alt_llist;

struct alt_llist_s {

alt_llist* next; /* Pointer to the next element in the list. */

alt_llist* previous; /* Pointer to the previous element in the list. */

};

#define ALT_LLIST_HEAD(head) alt_llist head = {&head, &head}

從定義中可知初始定義是一個指向自身的雙向鏈表結構。

2. 全局外設系統資源分配

l Nios II IDE生成的應用項目system.h中Lan91c111外設相關部分如下:

/*

* lan91c111_0 configuration

*

*/

#define LAN91C111_0_NAME "/dev/lan91c111_0"

#define LAN91C111_0_TYPE "altera_avalon_lan91c111"

#define LAN91C111_0_BASE 0x01200000

#define LAN91C111_0_IRQ 1

#define LAN91C111_0_IS_ETHERNET_MAC 1

#define LAN91C111_0_LAN91C111_REGISTERS_OFFSET 0x0300

#define LAN91C111_0_LAN91C111_DATA_BUS_WIDTH 32

l 分配外設系統資源:

在alt_sys_init.c中分配外設系統資源

/*

* Allocate the device storage

*

*/

ALTERA_AVALON_CFI_FLASH_INSTANCE( CFI_FLASH_0, cfi_flash_0 );

ALTERA_AVALON_JTAG_UART_INSTANCE( JTAG_UART_0, jtag_uart_0 );

ALTERA_AVALON_LAN91C111_INSTANCE( LAN91C111_0, lan91c111_0 );

從以上代碼中可以知Nios II以相對一致的宏定義了外設系統資源。

其中ALTERA_AVALON_LAN91C111_INSTANCE宏在altera_avalon_lan_91c111.h定義:

#define ALTERA_AVALON_LAN91C111_INSTANCE(name, dev) \

alt_avalon_lan91c111_if dev = \

{\

{\

ALT_LLIST_ENTRY,\

{\

0,\

name##_NAME,\

alt_avalon_lan91c111_init, \

alt_avalon_lan91c111_rx,\

},\

},\

name##_BASE + name##_LAN91C111_REGISTERS_OFFSET,\

name##_IRQ,\

name##_LAN91C111_DATA_BUS_WIDTH,\

0,\

0\

};

語法上理解這個宏有兩個關鍵點,首先定義了類型為alt_avalon_lan91c111_if的結構變數lan91c111_0(dev替換的結果),其次name##在編譯預處理時被替換為LAN91C111_0,例:name##_IRQ編譯後為LAN91C111_0_IRQ,這個宏在 system.h中被定義,進一步替換為1。

邏輯功能上理解這個宏,還需要明確alt_avalon_lan91c111_if類型的定義,在altera_avalon_lan_91c111.h中alt_avalon_lan91c111_if結構定義如下:

typedef struct

{

alt_lwip_dev_list lwip_dev_list;

int base_addr;

int irq;

int bus_width;

sys_sem_t semaphore;

alt_u8 tx_packet_no; /* Number of packet allocated for Tx */

}alt_avalon_lan91c111_if;

上述結構定義中,base_addr、irq、bus_width在system.h中定義,sys_sem_t為設備使用信號量,將在設備初始化時被賦值,tx_packet_no在使用中分配。Alt_lwip_dev_list結構在alt_lwip_de.h中相關定義如下:

struct alt_lwip_dev

{

/* The netif pointer MUST be the first element in the structure */

struct netif* netif;

const char* name;

err_t (*init_routine)(struct netif*);

void (*rx_routine)();

};

typedef struct

{

alt_llist llist; /* for internal use */

alt_lwip_dev dev;

}alt_lwip_dev_list;

從以上代碼可知,alt_lwip_list中llist是設備鏈表,在宏中被賦為內容為NULL指針的結構。alt_lwip_dev_list中dev 結構中除netif被賦0外其他域都被設置,netif將在設備初始化時被設置,其中網路設備lan91c111的初始化函數和讀設備函數被設置, alt_avalon_lan91c111_init函數和alt_avalon_lan91c111_rx函數在網路設備驅動程序中定義,如果我們要開發其他網路晶元的驅動程序HAL就需要提供類似的函數。

1. 設備環境初始化

通過上一節的分析,我們清楚的看到,設備管理鏈表被定義為全局結構變數,設備資源在宏定義中被分配為全局變數,這些資源都是靜態的被定義和分配。設備環境初始化動態的組織這些資源數據,在alt_sys_init.c中alt_sys_ini()函數在main()函數前被執行,程序相關部分如下:

/*

* Initialise the devices

*/

void alt_sys_init( void )

{

ALTERA_AVALON_CFI_FLASH_INIT( CFI_FLASH_0, cfi_flash_0 );

ALTERA_AVALON_JTAG_UART_INIT( JTAG_UART_0, jtag_uart_0 ); ALTERA_AVALON_LAN91C111_INIT( LAN91C111_0, lan91c111_0 );

}

alt_sys_init函數中相關設備環境初始化函數被調用,ALTERA_AVALON_LAN91C111_INIT是一個宏被定義在altera_avalon_lan91c111.h中:

#define ALTERA_AVALON_LAN91C111_INIT(name, dev) \

if (name##_IRQ == ALT_IRQ_NOT_CONNECTED) \

{ \

ALT_LINK_ERROR ("Error: Interrupt not connected for " #dev ". " \

"The ALTERA Avalon lan91c111 driver requires that an "\

"interrupt is connected. Please select an IRQ for " \

"this device in SOPC builder."); \

} \

else if (name##_LAN91C111_DATA_BUS_WIDTH != 32) \

{ \

ALT_LINK_ERROR ("Error: Invalid configuration for " #dev ". " \

"The ALTERA Avalon lan91c111 driver currently only " \

"supports the configuration of MAC/PHY on the " \

"development board. Please select this option " \

"in SOPC builder."); \

} \

else \

{ \

alt_lwip_dev_reg(dev); \

}

以上代碼清楚的說明alt_lwip_dev_reg(dev)函數被執行,其參數宏替換后應該為 lan91c111_0,而 lan91c111_0在第2節敘述中可知被定義為alt_avalon_lan91c111_if的全局變數。

函數alt_lwip_dev_reg 在alt_lwip_dev.h中被定義為以下宏:

#define alt_lwip_dev_reg(dev) alt_llist_insert(&alt_lwip_device_list, &dev.lwip_dev_list.llist)

函數調用被轉換成alt_llist_insert(&alt_lwip_device_list,& lan91c111_0.lwip_dev_list.llist);前一個參數是我們在第1節中敘述的全局鏈表結構,后一個參數是第2節中敘述的設備鏈表地址。通過上述分析,我們知道設備環境初始化被具體為設備雙向環形鏈表結構的增加,在實際應用開發中我們也可以通過類似的手法管理設備。下面我們具體的分析alt_llist_insert()函數。

Alt_llist_insert()函數在alt_llist.h中定義:

static ALT_INLINE void ALT_ALWAYS_INLINE alt_llist_insert(alt_llist* list,

alt_llist* entry)

{

entry->previous = list;

entry->next = list->next;

 

list->next->previous = entry;

list->next = entry;

}

網路協議棧和網路設備初始化
       Nios II IDE環境中集成了ucosII和lwip,lwip必須在ucos的支持下使用。在Nios II IDE中我們可以選擇Simple Socket Server項目模板來創建網路支持的項目,項目主文件main函數一般都會有以下程序行:

/*

* Our very first call in an lwIP example design is to start up lwIP TCP/IP

* stack. We specify a MicroC/OS-II thread priority for the tcp_ip thread,

* as well as a call-back routine, init_done_func(), which is called once

* the stack is alive and well.

*/

lwip_stack_init(LWIP_TCPIP_TASK_PRIORITY, init_done_func, 0);

……

/*

* As with all MicroC/OS-II designs, once the initial thread(s) and

* associated RTOS resources are declared, we start the RTOS. That's it!

*/

OSStart();

第一行語句初始化網路協議棧和網路設備初始化,OSStart()啟動UCOS多任務實時系統。

在上一篇敘述中我們分析了網路設備分配了系統資源並加入到網路設備鏈表中,但網路介面晶元和相關介面電路並未被初始化,現在我們來逐步分析Nios II的網路協議棧是如何建立並初始化底層設備的,我們分析的側重點不是lwip,而是準備寫自己的網路HAL,所以我們分析的重點是網路HAL和lwip 結合的部分。

Lwip_stack_init函數在alt_lwip_dev.c中定義,其第二個參數為回調初始化函數,Lwip_stack_init定義如下:

void lwip_stack_init(int thread_prio, void (* initfunc)(void *), void *arg)

{

sys_init();

#ifdef STATS

stats_init();

#endif /* STATS */

mem_init();

memp_init();

pbuf_init();

netif_init();

tcpip_init(thread_prio, initfunc, arg);

return;

}

其中tcpip_init()函數中在啟動tcpip任務時回調initfunc函數即init_done_func函數,init_done_func 函數在用戶主程序中(一般和main函數在同一文件中)。在init_done_func函數中初始化乙太網設備:

/*

* At this point LWIP has been initialized, but the Ethernet interface has

* not; the initialise_lwip_devices() call does so, adding in MicroC-OS/II

* threads for low-level Ethernet MAC interface and TCP protocol timer.

*/

if (!lwip_devices_init(ETHER_PRIO))

die_with_error("[tcpip_init_done] Fatal: Can't add ethernet interface!");

 

在lwip_devices_init(ETHER_PRIO)函數中,分配netif空間,並調用

dev_list_ptr->dev.netif =netif_add(dev_list_ptr->dev.netif,

&ipaddr, &netmask, &gw,

(void*)dev_list_ptr, dev_list_ptr->dev.init_routine,

tcpip_input);

}

在設備環境初始化時被設置的dev.init_routine被調用,設置網路介面電路和晶元寄存器完成網路設備初始化。




[admin via 研發互助社區 ] Nios ii設備管理分析已經有1420次圍觀

http://cocdig.com/docs/show-post-43271.html