RL-ARM版本:4.22 以太网PHY:DM9161 处理器:STR912FAW4x 软件平台:裸奔 编译环境:MDK-ARM Professional Version: 4.23 目标:固定IP,ping通
如果Keil提供了处理器的MAC驱动,并且驱动与PHY匹配的话,那么RL-TCPnet的实现超简单。Keil提供了STR9的驱动,不过那是为STE100P写的,而我用的是DM9161,驱动不能直接用,因此费了一些脑筋。 RL-TCPnet可独立于RTX内核运行,为了降低调试难度,我采用了裸奔的方式。 1. 添加并修改Net_Config.c 从Keil\ARM\RL\TCPnet\Config复制Net_Config.c,并修改如下:
去掉不用的模块。UDP要选上,因为ping的ICMP包要用到。 2. 添加函数库 从\Keil\ARM\RV31\LIB复制TCP_ARM_L.lib,并添加到MDK。 3. 添加并修改驱动 从\Keil\ARM\RL\TCPnet\Drivers复制STR9_ENET.c和STR9_ENET.h。 对比STE100P和DM9161的手册,发现两个芯片的寄存器0~6内容基本相同(业内标准??),于是我将STE100P特有的寄存器定义去掉,只保留相同的内容(STR9_ENET.h文件):
/* PHY Registers */
#define PHY_REG_XCR 0 /* XCVR Control Register */
#define PHY_REG_XSR 1 /* XCVR Status Register */
#define PHY_REG_PID1 2 /* PHY Identifier 1 */
#define PHY_REG_PID2 3 /* PHY Identifier 2 */
#define PHY_REG_ANA 4 /* Auto-Negotiation Advertisement */
#define PHY_REG_ANLPA 5 /* Auto-Neg. Link Partner Abitily */
#define PHY_REG_ANE 6 /* Auto-Neg. Expansion Register */
//#define PHY_REG_XCIIS 17 /* XCVR Config. and Interrupt Status */
//#define PHY_REG_XIE 18 /* XCVR Interrupt Enable Register */
//#define PHY_REG_100CTR 19 /* 100Base-TX PHY Control/Status */
//#define PHY_REG_XMC 20 /* XCVE Mode Control Register */
编译,提示PHY_REG_XCIIS未定义,代码在STR9_ENET.c的此处:
regv = read_PHY (PHY_REG_XCIIS);
if (regv & 0x0100) {
这两行的作用是判断是否全双工,可以通过读取寄存器0来实现:
regv = read_PHY (PHY_REG_XSR);
if (regv & 0x5000) {
根据DM9161的PHY ID和PHYAD[0~4]管脚的复位电平,将STR9_ENET.h这两行
#define STE100P_DEF_ADR 0x0000 /* Default PHY device address */
#define STE100P_ID 0x1C040010 /* PHY Identifier */
改为:
#define PHY_DEV_ADDR 1 /* PHY device address */
#define PHY_ID 0x0181B8A0 /* PHY Identifier */
同时修改STR9_ENET.c相关内容。 init_ethernet函数:
if (((id1 << 16) | (id2 & 0xFFF0)) == PHY_ID) {
write_PHY函数:
ENET_MAC->MIIA = (PHY_DEV_ADDR << 11) | (PhyReg << 6) | MIIA_WR | MIIA_BUSY;
read_PHY函数:
ENET_MAC->MIIA = (PHY_DEV_ADDR << 11) | (PhyReg << 6) | MIIA_BUSY;
最后,由于带__irq关键字的中断函数在裸奔时无法正常运行,将STR9_ENET.c文件中的所有__irq关键字去掉。
顺便说一下,这个驱动采用的是中断方式。根据Keil的手册,RL-TCPnet的以太网驱动有两种方式:轮询方式和中断方式。这里我没有看到poll_ethernet函数,而init_ethernet函数配置了中断入口,因此是中断方式。 4. 编写main.c 代码如下:
#include <rtl.h>
bool g_100mstimeout = FALSE; //这个标志在100ms定时中断置为TRUE
void timer_poll () {
if (g_100mstimeout) {
timer_tick (); // RL-TCPnet function
g_100mstimeout = FALSE;
}
}
int main (void) {
//此处初始化100ms定时器和外围时钟等
init_TcpNet ();
while (1) {
timer_poll ();
main_TcpNet ();
}
}
5. 注意事项 (1)如果PHY的时钟信号使用独立晶振,不使用STR9的P5.2,那么需要修改STR9_ENET.c中init_ethernet函数的IO初始化代码,禁止P5.2输出。不这样做的话,P5.2高频率悬空,对板子的EMC性能有影响。 (2)采用2008版STR91x.s在裸奔的时候无法正常运行,我采用的是2006版的文件。 (3)裸奔的时候STR91x.s中的Setup Library Exception Handlers选项必须打开,否则中断函数不正常。 有意思的是,以上(2)(3)两点以及__irq关键字都是与使用RTX的情况相反。原因不清楚,暂时没有去研究。
6. 参考资料 http://download.csdn.net/detail/zoogar/4003823 -- DM9161手册 http://download.csdn.net/detail/zoogar/4003811 -- STE100P手册 http://download.csdn.net/detail/zoogar/3983092 -- RL-ARM User's Guide http://download.csdn.net/detail/zoogar/3983085 -- Building Applications with RL-ARM - Getting Started http://bbs.eeworld.com.cn/thread-192539-1-3.html -- 云*飞扬写的网络开发笔记 http://bbs.eeworld.com.cn/thread-285929-1-1.html -- shilaike写的Realtime库学习心得 |