📄 halat91rm9200emac.c
字号:
/* * 修改记录: * 20060517 实现at91rm9200EMAC的HAL,该HAL目前支持网络组件的DLL。 * 20060706 修改at91rm9200EMAC在M4下实现,将mac地址和通讯方式提出让用户配置。 *//** * @file halat91rm9200EMAC.c * @brief * <li>功能:实现at91rm9200EMAC的HAL,该HAL目前支持网络组件的DLL</li> * @date 20060517 *//****************************** 引用部分 *********************************/#include <board.h> //引用at91rm9200目标板定义。#include <delta.h> //标准库函数。#include <string.h> //标准库函数。#include "halAt91rm9200EMAC.h" //引用at91rm9200EMAC定义。/****************************** 声明部分 *********************************/T_MODULE T_WORD At91rm9200EmacEntry();T_MODULE T_WORD AT91F_EMAC_Init(T_VOID *vpEtherDevData, tpAT91_EMAC tpEmac,T_UWORD pTdList);T_MODULE T_WORD AT91F_MDIO_StartupPhy(T_VOID *vpEtherDevData, tpAT91_EMAC tpEmac);T_MODULE T_VOID SetFHYState(T_VOID *vpEtherDevData, T_WORD Speed,T_WORD Mode);T_MODULE T_UWORD MiiStationRead(T_UWORD PhyInAddr,T_UWORD PhyAddr);T_MODULE T_VOID MiiStationWrite(T_UWORD PhyInAddr,T_UWORD PhyAddr, T_UWORD PhyWrData);T_MODULE T_BOOL Probe(T_HAL_AT91RM9200EMAC_DEV_DATA *tpEtherDevDataTable);T_MODULE T_VOID DelayMilSecs(T_WORD MilSeconds);/****************************** 定义部分 *********************************/#define NB_ETH_RX_PACKETS 8 //以太网包缓冲器数量。#define ETH_PACKET_SIZE 1536 //一个以太网包大小。typedef struct T_AT91RM9200EMAC_TdDescriptor{ T_UWORD addr; T_UWORD size;}tAT91RM9200EMAC_TdDescriptor, *tpAT91RM9200EMAC_TdDescriptor;//传输描述结构。T_MODULE T_BYTE baRxPacket[NB_ETH_RX_PACKETS*ETH_PACKET_SIZE];T_MODULE T_BYTE baAT91EmacTdlistBase[68];tpAT91RM9200EMAC_TdDescriptor tdList;/****************************** 实现部分 *********************************//** * @brief * 确认设备的存在,对于需要动态获得系统参数的设备 * 需要在此处把系统资源占用信息更新。 * * @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * * @return TRUE 成功。 * FALSE 失败。 */T_BOOL AT91RM9200EMAC_Find(T_VOID *vpEtherDevData){ T_HAL_AT91RM9200EMAC_DEV_DATA *tpEtherDevDataTable = (T_HAL_AT91RM9200EMAC_DEV_DATA *)vpEtherDevData; T_WORD retval; //确认AT91RM9200EMAC的存在,更新配置表项。 retval = Probe(tpEtherDevDataTable); if (retval != TRUE) { return FALSE; } return TRUE;}/** * @brief * 该接口用来获取HAL管理该设备需要的资源(主要指内存) * HAL不应该再再别的地方进行资源的获取工作,该接口获得的资源将都被传给HAL中其他接口使用。 * * @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * * @return TRUE 成功。 * FALSE 失败。 */T_BOOL AT91RM9200EMAC_GetResource(T_VOID *vpEtherDevData){ return TRUE;}/** * @brief * 关闭设备的中断。工作就是屏蔽在ChipIntEnable中使能的中断类型。 * * @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * * @return TRUE 成功(始终返回该值)。 */T_BOOL AT91RM9200EMAC_ChipIntDisable(T_VOID *vpEtherDevData){ pAT91C_BASE_AIC->AIC_IDCR = 0x1 << AT91C_ID_EMAC ;//关中断 pAT91C_BASE_AIC->AIC_ICCR = 0x1 << AT91C_ID_EMAC ;//清中断 return TRUE;}/** * @brief * 启动设备的运行,对设备进行基本初始化工作.主要工作包括: * 1.获取HAL为了驱动该设备所需要的系统资源,一般指内存空间; * 2.设置设备寄存器,让设备工作在正常状态下; * 3.注意该接口不要关心设备的中断开关状态。 * * @param[in] pEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * * @return * FALSE 失败 * TRUE 成功 */T_BOOL AT91RM9200EMAC_Start(T_VOID *vpEtherDevData){ T_HAL_AT91RM9200EMAC_DEV_DATA *tpEtherDevDataTable = (T_HAL_AT91RM9200EMAC_DEV_DATA *)vpEtherDevData; T_WORD status; rIOPBENABLE |= RESET_PHY; //PIOB 使能。 rIOPBOUTPUTEN |= RESET_PHY; //PIOB 输出使能。 rIOPBModVal |= RESET_PHY; //PIOB 写状态寄存器使能。 DelayMilSecs(800); rIOPBDataVal &= (~RESET_PHY); DelayMilSecs(1000); rIOPBDataVal |= RESET_PHY; DelayMilSecs(1000); //重启 Mobile 和 PHY。 status = At91rm9200EmacEntry(); //初始化EMAC接收包。 if (status) { printk("Error EMAC init: 0x%x", status); return FALSE; } rAT91C_EMAC_IDR = (T_UWORD) -1; //EMAC中断禁用寄存器初始化 AT91EMACCfgPMC(); //将电源控制器(PMC)提供给EMAC的外设时钟使能。 AT91PMCEnablePeriphClock(pAT91C_BASE_PMC, ((T_UWORD) 1 << AT91C_ID_PIOB)); //使能PIOB时钟(PID3)。 AT91PIODisable(pAT91C_BASE_PIOB,AT91C_PB29_IRQ0); //关闭PB29的PIO控制使能外设控制IRQ0 rAT91C_EMAC_IER = AT91C_EMAC_RCOM|AT91C_EMAC_TCOM|AT91C_EMAC_ROVR|AT91C_EMAC_RBNA|AT91C_EMAC_TOVR| AT91C_EMAC_TUND|AT91C_EMAC_RTRY|AT91C_EMAC_LINK |AT91C_EMAC_DONE; //EMAC中断使能寄存器初始化 AT91F_EMAC_Init(tpEtherDevDataTable, pAT91C_BASE_EMAC, (T_UWORD) tdList); //初始化EMAC。 return TRUE;}/** * @brief * 使能设备中断。设备也许有多种类型的中断,网络组件只关心发送和接收中断而已 * 其他中断类型的处理将由HAL本身负责解释并响应。所以此处使能的中断类型应该包括 * 发送中断和接收中断,其他类型中断由HAL自行决定。 * * @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * * @return TRUE 成功。 * FALSE 失败。 */T_BOOL AT91RM9200EMAC_ChipIntEnable(T_VOID *vpEtherDevData){ pAT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_EMAC; //使能中断。 return TRUE;}/** * @brief * 发送数据包,把从DLL传来的数据包发送出去。 * * @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * @param[in] bpKtBuf 数据包所在的缓存指针。 * @param[in] wKtLen 数据包大小。 * * @return * FALSE 失败 * TRUE 成功 */T_BOOL AT91RM9200EMAC_SendPkt(T_VOID *vpEtherDevData, T_BYTE *bpKtBuf, T_WORD wKtLen){ while(!pAT91C_BASE_EMAC->EMAC_TSR & AT91C_EMAC_BNQ) { ; //空循环(以太网发送缓冲器无队列一直循环直到有帧发送就绪)。 } if(wKtLen<60) { wKtLen = 60; //以太网最小发包长度60,不够要补齐。 } pAT91C_BASE_EMAC->EMAC_TAR = (T_UWORD)bpKtBuf;//帧首地址写入发送地址寄存器。 pAT91C_BASE_EMAC->EMAC_TCR = wKtLen; //写入将要发送的字节数目 对写入的非0值初始化发送。 return TRUE;}/** * @brief * 获取中断类型。当设备发生中断时,该接口将被调用。 * * @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * @param[in] uwVector 产生中断的中断向量。 * @param[out] *wpIntInfo 设备的中断信息,当返回的中断类型中包括"其他中断类型" * 时,该参数将被传给HandleOtherIntType的HAL接口。 * * @return 当发生多种中断类型时,把如下的返回值采用‘位或’运算后再返回。 * DEV_NO_INTERRUPT 该设备没有发生中断。 * DEV_INT_HAD_HANDLED 设备发生了中断,但已经被处理了。 * DEV_RECEIVE_INTERRUPT 设备发生了接收中断。 * DEV_SENDOVER_INTERRUPT 设备发生了发生中断。 * DEV_OHER_INTTYPE 设备发生了其他的中断类型。 */T_UWORD AT91RM9200EMAC_GetIntType(T_VOID *vpEtherDevData, T_UWORD uwVector, T_WORD *wpIntInfo){ T_UWORD ret = 0; T_UWORD status = 0; ///判断是EMAC中断还是PHY中断 if (AT91C_ID_EMAC == uwVector) //EMAC中断。 { status = rEMAC_ISR; //获取中断寄存器状态。 //无中断 if ((status & (AT91C_EMAC_DONE|AT91C_EMAC_RCOM|AT91C_EMAC_TCOM|AT91C_EMAC_RBNA|AT91C_EMAC_TOVR| AT91C_EMAC_TUND|AT91C_EMAC_RTRY|AT91C_EMAC_TBRE|AT91C_EMAC_TIDLE| AT91C_EMAC_LINK|AT91C_EMAC_ROVR|AT91C_EMAC_HRESP)) == 0) { return DEV_NO_INTERRUPT; } //接收完成 if (status & AT91C_EMAC_RCOM) { ret |= DEV_RECEIVE_INTERRUPT; } //发送完成 if ( status & AT91C_EMAC_TCOM ) { if (pAT91C_BASE_EMAC->EMAC_TSR&AT91C_EMAC_COMP) //发送完成。 { pAT91C_BASE_EMAC->EMAC_TSR|=AT91C_EMAC_COMP; //写1清除。 } ret |= DEV_SENDOVER_INTERRUPT; } //优先处理故障中断 if (status & (AT91C_EMAC_ROVR|AT91C_EMAC_RBNA)) //RX溢出状态或接收缓冲器无效。 { T_WORD i=0; for (i=0;i<NB_ETH_RX_PACKETS;i++) { if (!(tdList[i].addr & 0x1)) { pAT91C_BASE_EMAC->EMAC_RBQP = (T_UWORD)(tdList+i);//写入接收队列起始地址。 break; } } if (i>=NB_ETH_RX_PACKETS) { pAT91C_BASE_EMAC->EMAC_RBQP = (T_WORD)tdList; //写入接收队列起始地址。 } ret |= DEV_INT_HAD_HANDLED; } *wpIntInfo = status; rAIC_ICCR |= (1<<24); //中断清除。 rAIC_EOICR = 1 ; //写值标置中断处理结束。 }//end of if (AT91C_ID_EMAC == uwVector) else //PHY中断。 { ret = DEV_OHER_INTTYPE; } return ret;}/** * @brief * 获取设备当前接收到的数据包长度。当设备发生接收中断时,该接口将被调用。 * * @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * @param[out] wKtLen数据包的长度。 * * @return * FALSE 失败。 * TRUE 成功。 */T_BOOL AT91RM9200EMAC_GetPktLen(T_VOID *vpEtherDevData, T_WORD *wKtLen){// T_HAL_AT91RM9200EMAC_DEV_DATA *tpEtherDevDataTable = (T_HAL_AT91RM9200EMAC_DEV_DATA *)vpEtherDevData; if ((tdList->size) <= *wKtLen) { *wKtLen = tdList->size; return TRUE; } else { return FALSE; }}/** * @brief * 获取设备当前接收到的数据包的数据。当设备发生接收中断, * 且GetPktLen接口返回的数据包长度大于0时该接口将被调用。 * * @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * @param[in] wKtLen 数据包的长度 ,该参数即GetPktLen的返回值。 * * @return TRUE 成功。 * FALSE 失败。 */T_BOOL AT91RM9200EMAC_GetPktData(T_VOID *vpEtherDevData, T_BYTE * bpKtBuf, T_WORD wKtLen){// T_HAL_AT91RM9200EMAC_DEV_DATA *tpEtherDevDataTable = (T_HAL_AT91RM9200EMAC_DEV_DATA *)vpEtherDevData; T_WORD process = 0; T_BYTE *taddr = NULL; if(tdList->addr & 0x1) { taddr = (T_BYTE *)(tdList->addr & 0xFFFFFFFC); memcpy(bpKtBuf, taddr, tdList->size); tdList->addr &= ~0x01; process = 1; } if (0 == process) { return FALSE; } if (rAT91C_EMAC_RSR & AT91C_EMAC_REC) //已收到一个或多个帧,并置于存储器中。该位写 1 清除。 { (rAT91C_EMAC_RSR) |= AT91C_EMAC_REC; } return TRUE;}/** * @brief * 处理其他的中断类型。中断类型参数intInfo即在GetIntType中返回的中断。 * 状态信息。该信息由HAL自己负责定义和解释。 * * @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * @param[in] wpIntInfo 中断状态信息。 * * @return TRUE 成功。 * FALSE 失败。 */T_BOOL AT91RM9200EMAC_HandleOtherIsrType(T_VOID *vpEtherDevData, T_WORD wIntInfo){// T_HAL_AT91RM9200EMAC_DEV_DATA *tpEtherDevDataTable = (T_HAL_AT91RM9200EMAC_DEV_DATA *)vpEtherDevData; if (0 == wIntInfo) { T_UWORD PhyRdData = 0; T_UWORD i; T_UWORD mask = 0x1 << AT91C_ID_IRQ0; pAT91C_BASE_AIC->AIC_IDCR = mask; //在AIC中禁止该中断。 pAT91C_BASE_AIC->AIC_ICCR = mask; //在AIC中清除该中断。 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 = mask; //在AIC中使能该中断。 rAIC_ICCR |= (1<<AT91C_ID_IRQ0); //AIC中断清除寄存器置位清除中断。 rAIC_EOICR = 1; //AIC中断结束寄存器置位结束中断。 } return TRUE;}/** * @brief * 停止(或暂停)设备的运行,就是让该IO设备不能(正常)输入输出。 * 该函数一般就是要设置DISABLE位,或者把该设备设置为内循环模式 * 等。 * * @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * * @return TRUE 成功 (始终返回该值)。 */T_BOOL AT91RM9200EMAC_Stop(T_VOID *vpEtherDevData){ T_UWORD mask = 0x1 << AT91C_ID_SYS; pAT91C_BASE_AIC->AIC_IDCR = mask; //在AIC中禁止该中断。 pAT91C_BASE_AIC->AIC_ICCR = mask; //在AIC中清除该中断。 return TRUE;}/** * @brief * 释放HAL占用的资源(主要指在GetResource中获取到的资源)。 * * @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * * @return TRUE 成功。 * FALSE 失败。 */ T_BOOL AT91RM9200EMAC_ReleaseResource(T_VOID *vpEtherDevData){ return TRUE;}/** * @brief * 获取该网络设备的网络连接情况。 * * @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。 * @param[out] wplineStatus 连接状态。 DNET_IFOPERSTATUS_UP 或者 DNET_IFOPERSTATUS_DOWN。 * * @return FALSE 失败。 * TRUE 成功。 */T_BOOL AT91RM9200EMAC_LineCheck(T_VOID *vpEtherDevData, T_WORD *wplineStatus){ return FALSE;}/** * @brief * 获取设备的MAC地址。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -