ENC28J60學(xué)習(xí)筆記——AVRNET項(xiàng)目
1前言
嵌入式以太網(wǎng)開發(fā),可以分為兩個部分,一個是以太網(wǎng)收發(fā)芯片的使用,一個是嵌入式以太網(wǎng)協(xié)議棧的實(shí)現(xiàn)。以太網(wǎng)收發(fā)芯片的使用要比串口收發(fā)芯片的使用復(fù)雜的多,市面上流通比較廣泛的以太網(wǎng)收發(fā)芯片種類還不少,有SPI接口的ENC28J60,也有并口形式的RTL8019S,CS8900A等。嵌入式以太網(wǎng)協(xié)議棧有著名的uIP協(xié)議棧,Lwip協(xié)議棧,還有其他嵌入式高手開發(fā)的協(xié)議棧。無論是硬件還是軟件,都無法分出高下,適合項(xiàng)目需求的才是最好的。
1.1 寫作理由
在前言的最后,再說明一下我寫作的理由。以前從淘寶上購買過ENC28J60,店家信誓旦旦地說能提供51 AVR LPC STM32等多個平臺的代碼,可以實(shí)現(xiàn)一個網(wǎng)頁控制LED。頭腦一熱買了回來,買回來才發(fā)現(xiàn),店家提供的資料零零散散,非常難懂,雖然不貴僅僅需要40多元,現(xiàn)在只需要20多元。但是總感覺有欺騙的嫌疑,這也可以映射出中國人做技術(shù)買賣的原則,產(chǎn)品多是實(shí)物而非服務(wù)。幾經(jīng)周轉(zhuǎn),發(fā)現(xiàn)原來這些ENC28J60的代碼都出自一個地方——AVRNET,源自老外的一個開源項(xiàng)目。把最原始的代碼拿來細(xì)細(xì)品味,以太網(wǎng)協(xié)議就不那么神秘了。在這里說一下ENC28J60的使用,熟悉了ENC28J60的驅(qū)動可以分幾步走。第一步,通過ENC28J60移植uIP或者lwIP協(xié)議棧,實(shí)現(xiàn)TCP或是UDP通信,第二,順著AVRNET項(xiàng)目走,實(shí)現(xiàn)一個簡單的web服務(wù)器,運(yùn)行靜態(tài)或者動態(tài)網(wǎng)頁。嵌入式以太網(wǎng)和計(jì)算機(jī)以太網(wǎng)開發(fā)不同,對于TCP通信而言沒有windwos socke用,對于網(wǎng)頁編程而言也沒有ISS或PHP,所示實(shí)現(xiàn)起來會比較麻煩,但是也非常有樂趣。
1.2 平臺說明
硬件平臺 Atmega32 + proteus 7.10+WinPcap
編譯平臺 AVR Studio 6
關(guān)于硬件平臺,由于AVRNET項(xiàng)目采用ATmega32,分析的時候也采用Atmega32。就ENC28J60而言,對于其他的平臺,例如STM32或是MSP而言只需要修改SPI操作即可。由于沒有硬件平臺,所以使用proteus仿真,注意仿真以太網(wǎng)是proteus需要安裝WinPcap。
關(guān)于編譯平臺,AVRNET項(xiàng)目使用的是AVR Stdui 4.XX。這個版本稍顯老舊,我就進(jìn)行了相關(guān)修改,在AVR Studio 6中重新編譯,并修正了幾個錯誤。當(dāng)然其他的編譯平臺也適用。
總結(jié)一句,平臺選用原則——“求同存異”。
1.3 資料準(zhǔn)備
以太網(wǎng)開發(fā)是非常復(fù)雜的工作,在開始之前最好先大致瀏覽一些ENC28J60的使用手冊,MICROCHIP可以下載,中文版本閱讀非常方便。除此之外,需要認(rèn)真閱讀TCP IP相關(guān)知識,推薦一本圖書《嵌入式Internet TCP/IP基礎(chǔ)、實(shí)現(xiàn)和應(yīng)用》。
嵌入式開發(fā)總是一個反復(fù)借鑒的過程。該部分代碼參考了AVRNET項(xiàng)目和奮斗開發(fā)板的相關(guān)范例。AVRNET項(xiàng)目網(wǎng)址鏈接http://www.avrportal.com/?page=avrnet。
2寄存器和寄存器操作
ENC28J60的寄存器很多,操作這些寄存器需要一個良好的代碼組織工作。在AVRNET項(xiàng)目中,把ENC28J60的驅(qū)動分解成ENC28J60.h文件和ENC28J60.c文件。H文件中主要描述ENC28J60寄存器的基本定義,而C文件主要實(shí)現(xiàn)了這些寄存器的操作。
2.1寄存器定義
首先分析一下ENC28J60頭文件。閱讀數(shù)據(jù)手冊之后,會發(fā)現(xiàn)ENC28J60寄存器數(shù)量較多,通過分析和整理,操作ENC28J60的寄存器需要注意以下3點(diǎn)。
(1) 共有三種不同形式的寄存器——控制寄存器,以太網(wǎng)寄存器和PHY寄存器,不同的寄存器以不同的字母開頭,以E、MA和MI加以區(qū)分。操作這三種不同的寄存器需要不同的組合命令。
(2) 寄存器被分布在4個不同的bank中,也就是說存在地址相同的寄存器,但是這些寄存器卻位于不同的分區(qū)中,在操作寄存器之前必須選中正確的bank。
(3)雖然存在4個bank,但是有5個寄存器在4個bank的位置相同,它們是EIE、EIR、ESTAT、ECON1、ECON2。不言而喻,這5個寄存器將會非常重要。
AVRNET項(xiàng)目中,寄存器被定義成8位長度,而這8位長度包含了三個部分,地址bit7(最高位)用以區(qū)分PHY和MAC寄存器;地址bit6和bit5用以區(qū)分BANK,2位空間正好區(qū)分4個BANK;地址的最后5位才是寄存器的地址。通過這種方式就可以區(qū)分所有的寄存器了。列舉了幾行代碼。由于頭文件很長,所以不全部列出。
// bank0寄存器
#defineERDPTL (0x00|0x00)
#defineERDPTH (0x01|0x00)
#defineEWRPTL (0x02|0x00)
// bank1寄存器
#defineEHT0 (0x00|0x20)
#defineEHT1 (0x01|0x20)
#defineEHT2 (0x02|0x20)
// bank2寄存器
#defineMACON1 (0x00|0x40|0x80)
#defineMACON2 (0x01|0x40|0x80)
#defineMACON3 (0x02|0x40|0x80)
//bank3寄存器
#defineMAADR1 (0x00|0x60|0x80)
#defineMAADR0 (0x01|0x60|0x80)
#defineMAADR3 (0x02|0x60|0x80)
例如ERDPTH為位于BANK0的以太網(wǎng)寄存器,第一個數(shù)字0x01代表BANK0中的地址,該地址為0x01,第二個數(shù)字0x00代表BANK編號,該編號為0,意味第0個BANK;EHT1為位于BANK1中的控制寄存器,第二個0x20代表BANK地址為1,請注意由于BANK編號被保存在bit6和bit5,所以此處為0x20,絕不是0x10;MACON2為位于bank2的以太網(wǎng)寄存器,第一個數(shù)字0x01代表在該BANK中的寄存器地址,第二個數(shù)字0x40代表BANK編號,而第三個數(shù)字0x80代表該寄存器為以太網(wǎng)寄存器或是PHY寄存器,這些寄存器的操作和控制寄存器有區(qū)別。
為了方便寄存器操作,h文件中還定義了寄存器地址操作的掩碼,簡單而言就是需要查看哪些位,不需要查看哪些位。
/*寄存器地址掩碼*/
#defineADDR_MASK 0x1F
/*存儲區(qū)域掩碼*/
#defineBANK_MASK 0x60
/* MAC和MII寄存器掩碼*/
#defineSPRD_MASK 0x80
另外還有比較特殊的5個控制寄存器,EIE,EIR,ESTAT,ECON2和ECON1
/*關(guān)鍵寄存器*/
#defineEIE 0x1B
#defineEIR 0x1C
#defineESTAT 0x1D
#defineECON2 0x1E
#defineECON1 0x1F
2.2寄存器操作命令
寄存器操作命令也可稱為寄存器操作碼。為了實(shí)現(xiàn)寄存器的操作,ENC28J60定義了6+1個寄存器操作命令(操作碼)。操作相關(guān)寄存器至少有讀寄存器命令,寫寄存器命令;發(fā)送或接收以太網(wǎng)數(shù)據(jù)則必有寫緩沖區(qū)命令或讀緩沖區(qū)命令;為了加快操作,對于某些控制寄存器而言還可以有置位或者清零某位的命令;最后加上一個軟件復(fù)位命令,錦上添花。
/* 讀控制寄存器 */
#define ENC28J60_READ_CTRL_REG 0x00
/* 讀緩沖區(qū) */
#define ENC28J60_READ_BUF_MEM 0x3A
/* 寫控制寄存器 */
#define ENC28J60_WRITE_CTRL_REG 0x40
/* 寫緩沖區(qū) */
#define ENC28J60_WRITE_BUF_MEM 0x7A
/* 位域置位 */
#define ENC28J60_BIT_FIELD_SET 0x80
/* 位域清零 */
#define ENC28J60_BIT_FIELD_CLR 0xA0
/* 系統(tǒng)復(fù)位 */
#define ENC28J60_SOFT_RESET 0xFF
復(fù)制代碼
2.3接收和發(fā)送緩沖區(qū)分配
以太網(wǎng)數(shù)據(jù)的接收和發(fā)送離不開驅(qū)動芯片內(nèi)部的RAM,也可稱之為硬件緩沖區(qū)。ENC28J60包括8K的硬件緩沖區(qū),該硬件緩沖區(qū)一部分被接收緩沖區(qū)使用,另一部分為發(fā)送緩沖區(qū)使用。操作ENC28J60的最終目的為操作該硬件緩沖區(qū)。執(zhí)行以太網(wǎng)發(fā)送命令時,向發(fā)送緩沖區(qū)中填充數(shù)據(jù),并觸發(fā)相關(guān)寄存器發(fā)送以太網(wǎng)數(shù)據(jù);執(zhí)行以太網(wǎng)接收命令時,通過查詢相關(guān)寄存器或者外部中斷的方式獲得以太網(wǎng)數(shù)據(jù)輸入事件,接著從接收緩沖區(qū)中讀取相關(guān)數(shù)據(jù)。
(1) 把緩沖區(qū)劃分為兩個部分。把8K的硬件緩沖區(qū)劃分為兩個部分至少需要四個參數(shù),接收緩沖區(qū)需要一個起始地址和一個結(jié)束地址加以描述,發(fā)送緩沖區(qū)也需要一個起始地址和一個結(jié)束地址加以描述。最理想的方式,兩個緩沖區(qū)完全占據(jù)