原文转自:http://user.qzone.qq.com/345630492?ptlang=2052
是最近我们组做mcf52259开发板过程中一个demo测试程序
MCF52259_FEC—Fast Ethernet Controller<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
好久没写总结了,游戏一天现在也没什么状态干活,就来总结下近来的成果吧。
调Coldfire的以太网花的时间比较长,以前一直以为这块很难,有种畏惧心理,现在回过头来看看,要是不加协议的话跟IIC、SPI以及串口也相差不到哪去。最大的体会就是以太网的速度快的惊人,而且发送、接收数据很智能。
这次用的板子是我们自己做的开发板,主芯片MCF52259,标称最高主频<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />80M。呵呵,试过把它倍频到120M,依然正常工作!哈哈,没想到我们玩的也可以超频吧。它只有FEC即以太网控制器,并没有收发器模块,所以要外扩收发器PHY,这里用的是国家半导体的DP83848,给我的感觉依然是智能。支持10/100Mb/ps,MII……等等一大堆。
FEC的功能给我的感觉就是智能地控制数据的收与发。当有数据发送时,只要把数据存到缓冲区内并置位发送描述符的Ready位,并告诉FEC发送数据就绪它就自动完成数据的发送,结束后FEC会自动将发送描述符的Ready位清0;当有数据发过来时它会检查是否有接收描述符的empty位为1,要有的话就把数据放到那个描述符对就的接收缓冲区中,并将接收描述符的empty位清零,以告诉我们接收数据完成。这里有个其它通信方式没有的东西,那就是发送、接收描述符了,因为以太网的速度非常快,需要要的接收、发送缓冲区都很大,FEC模块并没有这么大的存储空间,因此使用芯片的RAM作为缓冲区。描述符的功能就是用来描述缓冲区的各种状态、数据长度以及缓冲区在RAM中的起始位置,FEC就通过描述符来控制数据传输。
就算不用协议,这块多多少少还是会涉及到一些协议方面的东西,要好好看资料了。而且后叙的工作还很多很多。
下面就是FEC初始化及,发送接收数据不用协议裸跑的代码:
/*
*初始化FEC,及接收发送描术符,系统MAC等
*/
void fec_init(uint8 mac_addr_fec[6])
{
MCF_FEC_ECR=MCF_FEC_ECR_RESET;
while(MCF_FEC_ECR&MCF_FEC_ECR_RESET)
{
;
}
MCF_FEC_EIMR=MCF_FEC_EIMR_MASK_ALL;
MCF_FEC_EIR=MCF_FEC_EIR_CLEAR_ALL;
MCF_FEC_PALR=(uint32)(0
|mac_addr_fec[0]<<24|mac_addr_fec[1]<<16
|mac_addr_fec[2]<<8 |mac_addr_fec[3]);
MCF_FEC_PAUR=(uint32)(0
|mac_addr_fec[4]<<24|mac_addr_fec[5]<<16
|MCF_FEC_PAUR_TYPE(0x8808));
MCF_FEC_IALR=0;
MCF_FEC_IAUR=0;
MCF_FEC_GALR=0xFFFFFFFF;
MCF_FEC_GAUR=0xFFFFFFFF;
//Set receive buffer size
MCF_FEC_EMRBR=MCF_FEC_EMRBR_R_BUF_SIZE(0x62);
MCF_FEC_RCR=MCF_FEC_RCR_MAX_FL(1520)
|MCF_FEC_RCR_MII_MODE
|MCF_FEC_RCR_BC_REJ;
//|MCF_FEC_RCR_PROM;
//|MCF_FEC_RCR_DRT;
MCF_FEC_TCR=MCF_FEC_TCR_FDEN;
//80/(16*2)=2.5M
MCF_FEC_MSCR=MCF_FEC_MSCR_MII_SPEED(16);
BD_init();
MCF_FEC_ERDSR=(uint32)&RxBDs[0];
MCF_FEC_ETSDR=(uint32)&TxBDs[0];
MCF_FEC_MIBC=MCF_FEC_MIBC_MIB_DISABLE;
MCF_FEC_ECR=MCF_FEC_ECR_ETHER_EN;
MCF_FEC_RDAR=MCF_FEC_RDAR_R_DES_ACTIVE;
MCF_FEC_TDAR=MCF_FEC_TDAR_X_DES_ACTIVE;
}
/*
*src_data[]为要发送的数据
*destAdd[6]为目的MAC地址
*srcAdd[6]这本地MAC地址
*lenType为数据长度加类型
*len为是要发送的数据Byte数
*/
int8 FEC_FrameSend(uint8 src_data[],uint8 destAdd[6],uint8 srcAdd[6],uint16 lenType,uint16 len)
{
// uint8 i;
vuint8 * TxdataAd;
txbd_pt++;
if(txbd_pt>=NUM_TXBDS) txbd_pt=0;
while((TxBDs[txbd_pt].status&MCF_FEC_TxBD_R)==MCF_FEC_TxBD_R)
{
txbd_pt++;
if(txbd_pt>=NUM_TXBDS)
txbd_pt=0;
}
TxdataAd=TxBDs[txbd_pt].dataAD;
memcpy((uint8*)TxdataAd,(uint8*)destAdd,6);
TxdataAd+=6;
memcpy((uint8*)TxdataAd,(uint8*)srcAdd,6);
TxdataAd+=6;
*TxdataAd++=(uint8)(lenType>>8);
*TxdataAd++=(uint8)lenType;
memcpy((void*)TxdataAd,(void*)src_data,len);
TxBDs[txbd_pt].length=(uint16)(len+14);
TxBDs[txbd_pt].status|=0
|MCF_FEC_TxBD_L
|MCF_FEC_TxBD_TC
|MCF_FEC_TxBD_R;
MCF_FEC_TDAR=MCF_FEC_TDAR_X_DES_ACTIVE;
return 0;
}
//用查寻方式接收数据,接收到的数据放到dest_data[]中
int8 FEC_FrameReceive(uint8 dest_data[],uint16 *len)
{
vuint8* RxdataAd;
rxbd_pt++;
if(rxbd_pt>=NUM_RXBDS) rxbd_pt=0;
while((RxBDs[rxbd_pt].status&MCF_FEC_RxBD_E)==MCF_FEC_RxBD_E)
{
rxbd_pt++;
if(rxbd_pt>=NUM_RXBDS) rxbd_pt=0;
}
RxdataAd=RxBDs[rxbd_pt].dataAD;
*len=RxBDs[rxbd_pt].length;
memcpy((uint8*)dest_data,(uint8*)RxdataAd,*len);
RxBDs[rxbd_pt].status|=MCF_FEC_RxBD_E;
MCF_FEC_RDAR=MCF_FEC_RDAR_R_DES_ACTIVE;
return 1;
}
void BD_init(void)
{
uint8 i;
RxBDs=(BD*)((uint32)(rxbd+16)&0xFFFFFFF0);
TxBDs=(BD*)((uint32)(txbd+16)&0xFFFFFFF0);
RxBuff=(uint8*)((uint32)(rxbuffer+16)&0xFFFFFFF0);
TxBuff=(uint8*)((uint32)(txbuffer+16)&0xFFFFFFF0);
for(i=0;i<NUM_RXBDS;i++)
{
RxBDs.status=(0|MCF_FEC_RxBD_E);
RxBDs.length=0;
RxBDs.dataAD=&RxBuff[i*RX_BUFF_SIZE];
}
RxBDs[NUM_RXBDS-1].status|=MCF_FEC_RxBD_W;
for(i=0;i<NUM_TXBDS;i++)
{
TxBDs.status=(0
|MCF_FEC_TxBD_L
|MCF_FEC_TxBD_TC);
TxBDs.length=0;
TxBDs.dataAD=&TxBuff[i*TX_BUFF_SIZE];
}
TxBDs[NUM_TXBDS-1].status|=MCF_FEC_TxBD_W;
}
//用于数据copy
void memcpy(uint8* des,uint8* src,uint16 num)
{
while(num>0)
{
*des++=*src++;
num--;
}
}
用户1357320 2011-1-12 09:57