📄 halat91rm9200emac.c
字号:
* * @param[in vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * @param[out] bpmacAddr 存放MAC地址的缓存。 * * @return TRUE 成功 (始终返回该值)。 */T_BOOL AT91RM9200EMAC_GetMacAddr(T_VOID *vpEtherDevData, T_CHAR *bpmacAddr){ T_HAL_AT91RM9200EMAC_DEV_DATA *tpEtherDevDataTable = (T_HAL_AT91RM9200EMAC_DEV_DATA *)vpEtherDevData; memcpy(bpmacAddr, tpEtherDevDataTable->emacAddr, 6); return TRUE;}/** * @brief * 获取设备的MAC地址。 * * @param[in vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * @param[out] bpmacAddr 存放MAC地址的缓存。 * * @return TRUE 成功 (始终返回该值)。 */T_BOOL AT91RM9200EMAC_SetMacAddr(T_VOID *vpEtherDevData, T_CHAR *bpmacAddr){ T_HAL_AT91RM9200EMAC_DEV_DATA *tpEtherDevDataTable = (T_HAL_AT91RM9200EMAC_DEV_DATA *)vpEtherDevData; tpAT91_EMAC pEmac; memcpy(tpEtherDevDataTable->emacAddr,bpmacAddr, 6); pEmac->EMAC_SA1L = ((int)tpEtherDevDataTable->emacAddr[2] << 24) | ((int)tpEtherDevDataTable->emacAddr[3] << 16) | ((int)tpEtherDevDataTable->emacAddr[4] << 8) |tpEtherDevDataTable->emacAddr[5]; pEmac->EMAC_SA1H = ((int)tpEtherDevDataTable->emacAddr[0] << 8) | tpEtherDevDataTable->emacAddr[1]; return TRUE;}/** * @brief * 增加一个组播地址到该网卡 * * @param[in] vpHalDevData 设备数据块指针,该结构的类型由HAL定义 * * @param[in] bMacAddr 指向一个6字节的存储空间,内容为需要增加的组播MAC地址 * * @param[in] vMultiMacChain 指向一个组播地址链,该链上的组播地址应该都被设置进入该网卡.该链的结构是 * typedef struct ether_multi{ * char haddr[6]; //组播地址 * unsigned short emc_users; //该组播地址的用户数,对于驱动,不需要关心该参数 * struct ether_multi * next; //指向下一节点 * }ETHER_MULTI; * * typedef struct macforhash{ * unsigned char macaddr[6]; //要操作的组播MAC地址 * ETHER_MULTI * chainpointer; //该设备需要设置的组播地址链 * }T_MACHASH; * multiMacChian为 T_MACHASH 指针类型,该参数的使用是可选的. * 即,HAL中,增加组播地址的实现既可仅根据macaddr参数进行操作, * 也可以根据multiMacChain来全部重新设定网卡组播地址 * * @return * FALSE 失败 * TRUE 成功 */T_BOOL AT91RM9200EMAC_AddMultiAddr(T_VOID *vpEtherDevData, T_CHAR *bMacAddr, T_VOID *vMultiMacChain){ return TRUE;}/** * @brief * 删除该网卡的一个组播地址 * * @param[in] vpHalDevData 设备数据块指针,该结构的类型由HAL定义 * * @param[in] bMacAddr 指向一个6字节的存储空间,内容为需要删除的组播MAC地址 * * @param[in] vMultiMacChain 指向一个组播地址链,该链上的组播地址应该都被设置进入该网卡.该链的结构是 * typedef struct ether_multi{ * char haddr[6]; //组播地址 * unsigned short emc_users; //该组播地址的用户数,对于驱动,不需要关心该参数 * struct ether_multi * next; //指向下一节点 * }ETHER_MULTI; * * typedef struct macforhash{ * unsigned char macaddr[6]; //要操作的组播MAC地址 * ETHER_MULTI * chainpointer; //该设备需要设置的组播地址链 * }T_MACHASH; * multiMacChian为 T_MACHASH 指针类型,该参数的使用是可选的. * 即,HAL中,删除组播地址的实现既可仅根据macaddr参数进行操作, * 也可以根据multiMacChain来全部重新设定网卡组播地址 * * @return * FALSE 失败 * TRUE 成功 */T_BOOL AT91RM9200EMAC_DelMultiAddr(T_VOID *vpEtherDevData, T_CHAR *bMacAddr, T_VOID * vMultiMacChain){ return TRUE;}/** * @brief * 初始化AT91RM9200EMAC接收包。 * * @param[in] 无。 * * @return 0 成功; * -1 失败. */T_MODULE T_WORD At91rm9200EmacEntry(){ T_UWORD i; T_BYTE *rxPacket; rxPacket = (T_BYTE *)baRxPacket; //初始化描述结构 for (i = 0; i < NB_ETH_RX_PACKETS; ++i) { tdList[i].addr = ((unsigned int) (rxPacket + (i * ETH_PACKET_SIZE))) & 0xFFFFFFFC; tdList[i].size = 0; } tdList[NB_ETH_RX_PACKETS-1].addr |= 0x02; //设置最后一位。 return 0;}/** * @brief * 初始化AT91RM9200EMAC。 * * @param[in] pEmac 以太网MAC接口。 * @param[in] pTdList 传送描述符。 * * @return 0 成功; * -1 失败. */T_MODULE T_WORD AT91F_EMAC_Init(T_VOID *vpEtherDevData, tpAT91_EMAC pEmac,T_UWORD uwTdList){ T_HAL_AT91RM9200EMAC_DEV_DATA *tpEtherDevDataTable = (T_HAL_AT91RM9200EMAC_DEV_DATA *)vpEtherDevData; T_WORD status; AT91EMACCfgPIO(); //给EMAC分配引脚。 ///初始化MAC地址。 pEmac->EMAC_SA1L = ((int)tpEtherDevDataTable->emacAddr[2] << 24) | ((int)tpEtherDevDataTable->emacAddr[3] << 16) | ((int)tpEtherDevDataTable->emacAddr[4] << 8) | tpEtherDevDataTable->emacAddr[5]; pEmac->EMAC_SA1H = ((int)tpEtherDevDataTable->emacAddr[0] << 8) | tpEtherDevDataTable->emacAddr[1]; ///初始化寄存器 pEmac->EMAC_RBQP = uwTdList; //接收缓冲队列指针寄存器。 pEmac->EMAC_RSR &= ~(AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA);//接收状态寄存器 RX溢出 桢接收 缓冲器无效 都是写1清除。 pEmac->EMAC_CFG |= (AT91C_EMAC_CAF | AT91C_EMAC_NBC | AT91C_EMAC_RMII);//配置寄存器 接收所有有效祯 无广播 使能RMII模式。 pEmac->EMAC_CFG |= AT91C_EMAC_CLK; //MCK64位分频。 pEmac->EMAC_CTL |= (AT91C_EMAC_TE | AT91C_EMAC_RE); //控制寄存器 发送使能 接收使能。 status = AT91F_MDIO_StartupPhy(tpEtherDevDataTable, pEmac); //启动 PHY。 if ( status ) { return status; } return 0;}/** * @brief * 启动PHY。 * * @param[in] pEmac 以太网MAC接口。 * * @return 0 成功; * -1 失败. */T_MODULE T_WORD AT91F_MDIO_StartupPhy(T_VOID *vpEtherDevData, tpAT91_EMAC pEmac){ T_HAL_AT91RM9200EMAC_DEV_DATA *tpEtherDevDataTable = (T_HAL_AT91RM9200EMAC_DEV_DATA *)vpEtherDevData; T_UWORD PhyRdData = 0 ; T_UWORD i = 0; if(pEmac->EMAC_SR & AT91C_EMAC_LINK) { return 0; } if (0 == tpEtherDevDataTable->mobileEtherType) { SetFHYState(tpEtherDevDataTable, MBPS_AUTO,AUTO_NEGOTIATE); } else if(1 == tpEtherDevDataTable->mobileEtherType) { SetFHYState(tpEtherDevDataTable, MBPS10,HALF_DUPLEX); } else if(2 == tpEtherDevDataTable->mobileEtherType) { SetFHYState(tpEtherDevDataTable, MBPS10,FULL_DUPLEX); } else if(3 == tpEtherDevDataTable->mobileEtherType) { SetFHYState(tpEtherDevDataTable, MBPS100,HALF_DUPLEX); } else if(4 == tpEtherDevDataTable->mobileEtherType) { SetFHYState(tpEtherDevDataTable, MBPS100,FULL_DUPLEX); } ///phy操作 for (i = 0;i < 500;i++) { ; //空循环,延时。 } pAT91C_BASE_AIC->AIC_IDCR = 0x1 << AT91C_ID_IRQ0; pAT91C_BASE_AIC->AIC_ICCR = 0x1 << AT91C_ID_IRQ0; pAT91C_BASE_EMAC->EMAC_CTL |= AT91C_EMAC_MPE; //使能管理端口。 rAT91C_EMAC_MAN = (PHY_INT_REG | PHYHWADDR0 |AT91C_EMAC_R | AT91C_EMAC_HIGH | CODE) & ~AT91C_EMAC_LOW; for (i = 0;i < 1000;i++) { ; //空循环,延时。 } PhyRdData = (rAT91C_EMAC_MAN) & AT91C_EMAC_DATA ; pAT91C_BASE_EMAC->EMAC_CTL &= ~AT91C_EMAC_MPE; pAT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_IRQ0; rAIC_ICCR |= (1 << AT91C_ID_IRQ0); rAIC_EOICR = 1; MiiStationWrite(PHY_INT_REG, PHYHWADDR0,PHY_LINKUP_EN); return 0;}/** * @brief * 设置FHY。 * * @param[in] Speed 网络传输速度(10M ,100M)。 * @param[in] Mode 网络传输方式 。 * @return 无。 * */T_MODULE T_VOID SetFHYState(T_VOID *vpEtherDevData, T_WORD wSpeed,T_WORD wMode){ T_HAL_AT91RM9200EMAC_DEV_DATA *tpEtherDevDataTable = (T_HAL_AT91RM9200EMAC_DEV_DATA *)vpEtherDevData; T_UWORD FHYState = 0; FHYState = 0; FHYState = MiiStationRead(PHY_CNTL_REG,PHYHWADDR0); //读取物理维护寄存器的值。 if (AUTO_NEGOTIATE == wMode) //设置为自动协商。 { MiiStationWrite(PHY_CNTL_REG, PHYHWADDR0, ENABLE_AN|RESTART_AN); tpEtherDevDataTable->mobileEtherType = 0; } else //根据配置设置FHY。 { FHYState = FHYState&~ENABLE_AN; MiiStationWrite(PHY_CNTL_REG,PHYHWADDR0,FHYState); } if (MBPS10 == wSpeed) //10M。 { if (wMode == HALF_DUPLEX) //半双工。 { FHYState = FHYState&~PHY_FULLDUPLEX; //8 FHYState = FHYState&~DR_100MB; //13 MiiStationWrite(PHY_CNTL_REG,PHYHWADDR0,FHYState); tpEtherDevDataTable->mobileEtherType = 1; } else if (FULL_DUPLEX == wMode) //全双工。 { FHYState = FHYState&~DR_100MB; FHYState = FHYState|PHY_FULLDUPLEX; MiiStationWrite(PHY_CNTL_REG,PHYHWADDR0,FHYState); tpEtherDevDataTable->mobileEtherType = 2; } } else if (MBPS100 == wSpeed) //100M。 { if (HALF_DUPLEX == wMode) //半双工。 { FHYState = FHYState&~PHY_FULLDUPLEX; FHYState = FHYState|DR_100MB; MiiStationWrite(PHY_CNTL_REG,PHYHWADDR0,FHYState); tpEtherDevDataTable->mobileEtherType = 3; } else if (FULL_DUPLEX == wMode) //全双工。 { FHYState = FHYState|PHY_FULLDUPLEX; FHYState = FHYState|DR_100MB; MiiStationWrite(PHY_CNTL_REG,PHYHWADDR0,FHYState); tpEtherDevDataTable->mobileEtherType = 4; } } if (0 == tpEtherDevDataTable->mobileEtherType) { FHYState = MiiStationRead(PHY_STATUS_REG,PHYHWADDR0); if (FHYState & LINK_ON) { FHYState = MiiStationRead(PHY_TXCNTL_REG,PHYHWADDR0); while ((FHYState|PHY_STATE_AN_NOT_COMPLETE) == PHY_STATE_AN_NOT_COMPLETE) { FHYState = MiiStationRead(PHY_TXCNTL_REG,PHYHWADDR0); } if (FHYState & PHY_STATE_100) { pAT91C_BASE_EMAC->EMAC_CFG |= AT91C_EMAC_SPD; } else if (FHYState & PHY_STATE_10) { pAT91C_BASE_EMAC->EMAC_CFG &= ~AT91C_EMAC_SPD; } if (FHYState & PHY_STATE_FULL) { pAT91C_BASE_EMAC->EMAC_CFG |= AT91C_EMAC_FD; } else { pAT91C_BASE_EMAC->EMAC_CFG &= ~AT91C_EMAC_FD; } } } else if (1 == tpEtherDevDataTable->mobileEtherType) { pAT91C_BASE_EMAC->EMAC_CFG &= ~(AT91C_EMAC_SPD|AT91C_EMAC_FD); //十兆半双工。 } else if(2 == tpEtherDevDataTable->mobileEtherType) { pAT91C_BASE_EMAC->EMAC_CFG = (pAT91C_BASE_EMAC->EMAC_CFG | AT91C_EMAC_FD ) & ~AT91C_EMAC_SPD;//十兆全双工。 } else if(3 == tpEtherDevDataTable->mobileEtherType) { pAT91C_BASE_EMAC->EMAC_CFG = (pAT91C_BASE_EMAC->EMAC_CFG | AT91C_EMAC_SPD ) & ~AT91C_EMAC_FD;//百兆半双工。 } else if(4 == tpEtherDevDataTable->mobileEtherType) { pAT91C_BASE_EMAC->EMAC_CFG |= (AT91C_EMAC_SPD| AT91C_EMAC_FD); //百兆全双工。 }}/** * @brief * MII Interface Station Management Register Reads。 * * @param[in] PhyInAddr PHY中断寄存器地址。 * @param[in] PhyAddr PHY地址。 * @return PhyRdData 成功。 * */T_MODULE T_UWORD MiiStationRead(T_UWORD uwPhyInAddr,T_UWORD uwPhyAddr){ T_UWORD phyRdData; pAT91C_BASE_EMAC->EMAC_CTL |= AT91C_EMAC_MPE;//管理端口使能。 //10为读(01为写) 必须写入1以保证PHY管理祯有效 IEEE标准必须写入10读与写一样 必须写入0以保证PHY管理祯有效。 rAT91C_EMAC_MAN = (uwPhyInAddr | uwPhyAddr |AT91C_EMAC_R | AT91C_EMAC_HIGH | CODE) & ~AT91C_EMAC_LOW; while (!(rEMAC_ISR &AT91C_EMAC_DONE)) { ; //空循环。 } pAT91C_BASE_EMAC->EMAC_CTL &= ~AT91C_EMAC_MPE;//为0时强制MDIO为高阻态。 phyRdData = (rAT91C_EMAC_MAN) & AT91C_EMAC_DATA; return phyRdData ;}/** * @brief * MII Interface Station Management Register write。 * * @param[in] PhyInAddr PHY中断寄存器地址。 * @param[in] PhyAddr PHY地址。 * @param[in] PhyWrData 写入数据 * @return 无。 * */T_MODULE T_VOID MiiStationWrite(T_UWORD uwPhyInAddr,T_UWORD uwPhyAddr, T_UWORD uwPhyWrData){ //必须写入1以保证PHY管理祯有效 IEEE标准必须写入10读与写一样 必须写入0以保证PHY管理祯有效。 T_UWORD tmp = (uwPhyWrData | uwPhyInAddr | uwPhyAddr | AT91C_EMAC_HIGH | CODE |AT91C_EMAC_W) & ~AT91C_EMAC_LOW ; pAT91C_BASE_EMAC->EMAC_CTL |= AT91C_EMAC_MPE; //管理端口使能。 rAT91C_EMAC_MAN = tmp; //写物理维护寄存器。 while(!(rEMAC_ISR &AT91C_EMAC_DONE)) { ; //空循环。 } pAT91C_BASE_EMAC->EMAC_CTL &= ~AT91C_EMAC_MPE;//为0时强制MDIO为高阻态。}/** * @brief * 通过读取芯片的vendor,判断AT91RM9200EMAC是否存在。 * * @param[in] tpEtherDevDataTable 设备数据块指针,该结构的类型由HAL定义。 * @param[in] wIndex 该设备在系统中相同设备的索引。 * * @return * FALSE 失败 * TRUE 成功 */T_MODULE T_BOOL Probe(T_HAL_AT91RM9200EMAC_DEV_DATA *tpEtherDevDataTable){ T_WORD addr =(T_WORD)&baAT91EmacTdlistBase;//指向数组空间。 if (0 == (addr & 0x0c)) //偏移位 对齐(4位)。 { tdList = (tpAT91RM9200EMAC_TdDescriptor)addr; } else { tdList = (tpAT91RM9200EMAC_TdDescriptor)((addr&0xfffffffc) + 4); } return TRUE;}/** * @brief Mil延时 * * @param[in] MilSeconds 延时时间 * @return 无。 */T_MODULE T_VOID DelayMilSecs(T_WORD wMilSeconds){ T_WORD ii; for (ii=0;ii<wMilSeconds;ii++) { ; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -