嵌入式系統期中報告
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)是否有回有應,結果有回應,測試成功