嵌入式系統期中報告 ENC28J60 使用 SPI 的獨立乙太網路控制器 指導老師 : 陳慶瀚教授 學號 :995302031 姓名 : 曾錦華
目錄 一 ENC28J60 硬體週邊原理介紹... 3 1 原理介紹... 3 2 ENC28J60 由七个主要功能模組组成... 3 二 SIOC 的 Driver 設計及主要程式說明... 4 1 Main.c... 4 2 Spi.c... 5 3 WebServer.c... 6 4 ENC28J60.C... 7 5 ir_arp_udp_tcp.c... 11 三 SIOC 與 ENC28J60 的接線圖... 12 四 SIOC 驗證... 13
一 ENC28J60 硬體週邊原理介紹 1 原理介紹 A. ENC28J60 是帶有業界標準串列周邊介面 (Serial Peripheral Interface,SPI) 的獨立乙太網控制器 它可作為任何配備有 SPI 的控制器的乙太網介面 B. ENC28J60 符合 IEEE 802.3 的全部規範, 採用了一系列包過慮機制以對傳入數據封包進行限制 它還提供了一个内部 DMA 模組, 以實現快速數據吞吐和硬體支持的 IP 驗証和計算 與主控制器的通信通過兩個中斷引脚和 SPI 實現, 數據傳輸速率高達 10 Mb/s 兩個專用的引脚用於連接 LED, 進行網路活動狀態指示 C. 下圖為 ENC28J60 的架構圖 2 ENC28J60 由七个主要功能模組組成 : A. SPI 接口 扮演主控制器和 ENC28J60 之間通信通道 B. 控制寄存器 用於控制和監視 ENC28J60 C. 双端口 RAM 緩衝器 用於接收和發送數據包 D. 判優器 當 DMA 發送和接收模組發出請求時對 RAM 緩衝器的訪問進行控制 E. 總線接口 對通过 SPI 接收的數據和命令進行解析 F. MAC (Medium Access Control) 模組 實現符合 IEEE 802.3 標準的 MAC 邏輯 G. PHY( 物理層 ) 模組 對雙絞線上的模擬數據進行編碼和解碼 ENC28J60 架構圖
二 SIOC 的 Driver 設計及主要程式說明 1 Main.c int main(void) int rev; printf("set_system... \r\n"); /* System clocks configuration ---------------------------------------------*/ Set_System(); getchar(); printf("rcc_configuration... \r\n"); RCC_Configuration(); /* SPI1 configuration */ printf("spi1& GPIO configuration... \r\n"); SPI1_Init(); printf("webserver start... \r\n\n"); WebServer(); return rev; void RCC_Configuration(void) /* PCLK2 = HCLK/2 */ RCC_PCLK2Config(RCC_HCLK_Div2); /* Enable peripheral clocks --------------------------------------------------*/ /* GPIOA, GPIOB and SPI1 clock enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA RCC_APB2Periph_GPIOB RCC_APB2Periph_SPI1, ENABLE); /* SPI2 Periph clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
2 Spi.c void SPI1_Init(void) SPI_InitTypeDef SPI_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; /* Configure SPI2 pins: NSS, SCK, MISO and MOSI */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 GPIO_Pin_14 GPIO_Pin_15; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); /* Configure SPI1 pins: NSS, SCK, MISO and MOSI */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); /* SPI2 configuration */ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //spi 傳輸模式, 全雙工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //SPI operating mode SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI data size 8b or 16b SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //SPI_CPOL selects the serial clock steady state SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //the clock active edge for the bit capture //specifies whether the NSS signal is managed by hardware (NSS pin) or by software using the SSI bit SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //define the Baud Rate prescaler value which will be used to configure the transmit and receive SCK clock SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //data transfers start from MSB or LSB bit SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI2, &SPI_InitStructure); /* Enable SPI2 */ SPI_Cmd(SPI2, ENABLE);
3 WebServer.c #include <string.h> #include "enc28j60.h" #include "ip_arp_udp_tcp.h" #include "net.h" #include "WebServer.h" #include "stdio.h" const unsigned char mymac[6] = 0x54,0x55,0x58,0x10,0x00,0x24; const unsigned char myip[4] = 192,168,2,25; static unsigned int mywwwport =80; int WebServer(void) /*initialize enc28j60*/ printf("initialize enc28j60... \r\n"); enc28j60init((unsigned char *)mymac); printf("execute function init_ip_arp_udp_tcp \r\n"); init_ip_arp_udp_tcp((unsigned char *)mymac,(unsigned char *)myip,mywwwport);
4 ENC28J60.C #include "enc28j60.h" #include "spi.h" #include <stdio.h> void enc28j60init(unsigned char* macaddr) // initialize I/O ENC28J60_CSH(); enc28j60writeop(enc28j60_soft_reset, 0, ENC28J60_SOFT_RESET); NextPacketPtr = RXSTART_INIT; // Rx start enc28j60write(erxstl, RXSTART_INIT&0xFF); enc28j60write(erxsth, RXSTART_INIT>>8); // set receive pointer address enc28j60write(erxrdptl, RXSTART_INIT&0xFF); enc28j60write(erxrdpth, RXSTART_INIT>>8); // RX end enc28j60write(erxndl, RXSTOP_INIT&0xFF); enc28j60write(erxndh, RXSTOP_INIT>>8); // TX start enc28j60write(etxstl, TXSTART_INIT&0xFF); enc28j60write(etxsth, TXSTART_INIT>>8); // TX end enc28j60write(etxndl, TXSTOP_INIT&0xFF); enc28j60write(etxndh, TXSTOP_INIT>>8); // do bank 1 stuff, packet filter: // For broadcast packets we allow only ARP packtets // All other packets should be unicast only for our mac (MAADR) //The pattern to match on is therefore // Type ETH.DST // ARP BROADCAST // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9 // in binary these poitions are:11 0000 0011 1111 // This is hex 303F->EPMM0=0x3f,EPMM1=0x30 enc28j60write(erxfcon, ERXFCON_UCEN ERXFCON_CRCEN ERXFCON_PMEN); enc28j60write(epmm0, 0x3f);
enc28j60write(epmm1, 0x30); enc28j60write(epmcsl, 0xf9); enc28j60write(epmcsh, 0xf7); // do bank 2 stuff // enable MAC receive enc28j60write(macon1, MACON1_MARXEN MACON1_TXPAUS MACON1_RXPAUS); // bring MAC out of reset enc28j60write(macon2, 0x00); // enable automatic padding to 60bytes and CRC operations enc28j60writeop(enc28j60_bit_field_set, MACON3, MACON3_PADCFG0 MACON3_TXCRCEN MACON3_FRMLNEN MACON3_FULDPX); // set inter-frame gap (non-back-to-back) enc28j60write(maipgl, 0x12); enc28j60write(maipgh, 0x0C); // set inter-frame gap (back-to-back) enc28j60write(mabbipg, 0x12); // Set the maximum packet size which the controller will accept // Do not send packets longer than MAX_FRAMELEN: enc28j60write(mamxfll, MAX_FRAMELEN&0xFF); enc28j60write(mamxflh, MAX_FRAMELEN>>8); // do bank 3 stuff // write MAC address // NOTE: MAC address in ENC28J60 is byte-backward enc28j60write(maadr5, macaddr[0]); enc28j60write(maadr4, macaddr[1]); enc28j60write(maadr3, macaddr[2]); enc28j60write(maadr2, macaddr[3]); enc28j60write(maadr1, macaddr[4]); enc28j60write(maadr0, macaddr[5]); printf("maadr5 = 0x%x\r\n", enc28j60read(maadr5)); printf("maadr4 = 0x%x\r\n", enc28j60read(maadr4)); printf("maadr3 = 0x%x\r\n", enc28j60read(maadr3)); printf("maadr2 = 0x%x\r\n", enc28j60read(maadr2)); printf("maadr1 = 0x%x\r\n", enc28j60read(maadr1)); printf("maadr0 = 0x%x\r\n", enc28j60read(maadr0));
enc28j60phywrite(phcon1, PHCON1_PDPXMD); // no loopback of transmitted frames enc28j60phywrite(phcon2, PHCON2_HDLDIS); // switch to bank 0 enc28j60setbank(econ1); // enable interrutps enc28j60writeop(enc28j60_bit_field_set, EIE, EIE_INTIE EIE_PKTIE); // enable packet reception enc28j60writeop(enc28j60_bit_field_set, ECON1, ECON1_RXEN); void enc28j60writeop(unsigned char op, unsigned char address, unsigned char data) unsigned char dat = 0; ENC28J60_CSL(); // issue write command dat = op (address & ADDR_MASK); SPI1_ReadWrite(dat); // write data dat = data; SPI1_ReadWrite(dat); ENC28J60_CSH(); void enc28j60write(unsigned char address, unsigned char data) // set the bank enc28j60setbank(address); // do the write enc28j60writeop(enc28j60_write_ctrl_reg, address, data); void enc28j60phywrite(unsigned char address, unsigned int data) // set the PHY register address enc28j60write(miregadr, address); // write the PHY data
enc28j60write(miwrl, data); enc28j60write(miwrh, data>>8); // wait until the PHY write completes while(enc28j60read(mistat) & MISTAT_BUSY) //Del_10us(1); //_nop_(); void enc28j60setbank(unsigned char address) // set the bank (if needed) if((address & BANK_MASK)!= Enc28j60Bank) // set the bank enc28j60writeop(enc28j60_bit_field_clr, ECON1, (ECON1_BSEL1 ECON1_BSEL0)); enc28j60writeop(enc28j60_bit_field_set, ECON1, (address & BANK_MASK)>>5); Enc28j60Bank = (address & BANK_MASK);
5 ir_arp_udp_tcp.c // you must call this function once before you use any of the other functions: void init_ip_arp_udp_tcp(unsigned char *mymac,unsigned char *myip,unsigned char wwwp) unsigned char i=0; wwwport=wwwp; printf("ip address:"); while(i<4) ipaddr[i]=myip[i]; printf("%d.",ipaddr[i]); i++; printf("\n\n"); i=0; while(i<6) macaddr[i]=mymac[i]; i++;
三 SIOC 與 ENC28J60 的接線圖 Mapping Table Num SIOC ENC28J60 1 GND(1)- 白 GND(10) 2 VDD1(4)- 黃 VCC 3.3V(9) 3 PB13(22)- 橘 SCK(2) 4 PB14(23)- 紫 SO(4) 5 PB15(24)- 棕 SI(3) 6 PA8(25)- 紅 CS(1)
四 SIOC 驗證 1 將 build 好的 dfu 檔寫入 SIOC 後, 在 putty 將寫入的 mac address 和 ip address [ 192.168.2.25 ] 秀出 2 手動設定本機的 ip address [ 192.168.2.10 ], 設成 ENC28J60 中的 ip address 同一個網段
3 將網路線連接至 ENC28J60 後, 電腦右下會顯示 區域連線現在已連線速度 : 10.0 Mbps 4 確認本機的 ip address [ 192.168.2.10 ] 5 使用 ping 指令來確認 ENC28J60(ip : 192.168.2.25) 是否有回有應, 結果有回應, 測試成功
作業最晚於 5 月 26 日前繳交電子檔, 含 Word 檔和 project file,e-mail 寄至 : pierre@csie.ncu.edu.tw mail 主旨請寫 " 嵌入式系統設計期中作業 "