本帖最后由 guoqingli1123 于 2016-10-12 11:39 编辑
最近在调试MINI-STM32的DHCP。一开始调试的挺顺利,用家里的路由器很快就调试成功了。但后来在公司换了个路由器调试怎么都获取不了IP地址。电脑可以正常获取IP地址。很郁闷。网上也没有找到答案。不能DHCP的路由器是D-LINK,非常老的路由器,我又找了个路由器磊科的,比较新,试了一下很快获取了IP地址。很纳闷。为啥电脑用D-LINK,磊科的都可以,而STM32-MINI板不行。于是进行了抓包
如下所示
以上为DLINK的。可以看到DLINK提供的offer包,BOOTP标志为0x0000, 单播
此时STM32-MINI板没有发出Request包,获取DHCP失败
而电脑并没有按照单播的要求进行回复,而是直接回复了广播包,一下就获取到了IP地址
然后对磊科的路由器进行抓包如下
发现磊科路由器提供的offer包,bootp标志为0x8000, 组播
此时STM32-MINI板能够正确获取到IP地址。
我试了几个路由发现只要发出的是0x0000的都获取不到IP地址。0x8000的都能正确获取。猜测lwip不支持0x0000模式????
怎么修改还没有解决方案。原子哥。。。求助。。。。
ENC28J60初始化的问题。
u8 version;
u16 retry=0;
u32 temp;
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
memset((void *)&enc28j60_dev, 0, sizeof(dev_strucrt));
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE); //使能PA,C端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_4);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_4);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);
EXTI_InitStructure.EXTI_Line = EXTI_Line1;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
EXTI_ClearITPendingBit(EXTI_Line1);
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
SPI1_Init();
SPI_Cmd(SPI1, DISABLE);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
SPI1_SetSpeed(SPI_BaudRatePrescaler_8);
temp=*(vu32*)(0x1FFFF7F0);
if(sysSave->macSetEnable == 1)
{
memcpy(enc28j60_dev.macaddr, sysSave->mac, 6);
}
else
{
enc28j60_dev.macaddr[0]=MAC0;
enc28j60_dev.macaddr[1]=MAC1;
enc28j60_dev.macaddr[2]=MAC2;
enc28j60_dev.macaddr[3]=(temp>>16)&0XFF;
enc28j60_dev.macaddr[4]=(temp>>8)&0XFFF;
enc28j60_dev.macaddr[5]=temp&0XFF;
}
if(enc28j60_dev.macaddr[0] != MAC0)
enc28j60_dev.macaddr[0] = MAC0;
if(enc28j60_dev.macaddr[1] != MAC1)
enc28j60_dev.macaddr[1] = MAC1;
if(enc28j60_dev.macaddr[2] != MAC2)
enc28j60_dev.macaddr[2] = MAC2;
ENC28J60_RST=0;
G_TIME_DelayMs(10);
ENC28J60_RST=1;
G_TIME_DelayMs(10);
ENC28J60_Write_Op(ENC28J60_SOFT_RESET,0,ENC28J60_SOFT_RESET);
while(!(ENC28J60_Read(ESTAT)&ESTAT_CLKRDY)&&retry<250)
{
retry++;
G_TIME_DelayMs(1);
}
if(retry>=250)
return 1;
version=ENC28J60_Get_EREVID();
printf("ENC28J60 Version=%d ", version);
enc28j60_dev.NextPacketPtr=RXSTART_INIT;
//接收缓冲器由一个硬件管理的循环FIFO 缓冲器构成。
//寄存器对ERXSTH:ERXSTL 和ERXNDH:ERXNDL 作
//为指针,定义缓冲器的容量和其在存储器中的位置。
//ERXST和ERXND指向的字节均包含在FIFO缓冲器内。
//当从以太网接口接收数据字节时,这些字节被顺序写入
//接收缓冲器。 但是当写入由ERXND 指向的存储单元
//后,硬件会自动将接收的下一字节写入由ERXST 指向
//的存储单元。 因此接收硬件将不会写入FIFO 以外的单
//元。
//设置接收起始字节
ENC28J60_Write(ERXSTL,RXSTART_INIT&0XFF); //设置接收缓冲区起始地址低8位
ENC28J60_Write(ERXSTH,RXSTART_INIT>>8); //设置接收缓冲区起始地址高8位
//设置接收接收字节
ENC28J60_Write(ERXNDL,RXSTOP_INIT&0XFF);
ENC28J60_Write(ERXNDH,RXSTOP_INIT>>8);
//设置发送起始字节
ENC28J60_Write(ETXSTL,TXSTART_INIT&0XFF);
ENC28J60_Write(ETXSTH,TXSTART_INIT>>8);
//设置发送结束字节
ENC28J60_Write(ETXNDL,TXSTOP_INIT&0XFF);
ENC28J60_Write(ETXNDH,TXSTOP_INIT>>8);
//ERXWRPTH:ERXWRPTL 寄存器定义硬件向FIFO 中
//的哪个位置写入其接收到的字节。 指针是只读的,在成
//功接收到一个数据包后,硬件会自动更新指针。 指针可
//用于判断FIFO 内剩余空间的大小 8K-1500。
//设置接收读指针字节
ENC28J60_Write(ERXRDPTL,RXSTART_INIT&0XFF);
ENC28J60_Write(ERXRDPTH,RXSTART_INIT>>8);
//接收过滤器
//UCEN:单播过滤器使能位
//当ANDOR = 1 时:
/* //1 = 目标地址与本地MAC 地址不匹配的数据包将被丢弃
//0 = 禁止过滤器
//当ANDOR = 0 时:
//1 = 目标地址与本地MAC 地址匹配的数据包会被接受
//0 = 禁止过滤器
//CRCEN:后过滤器CRC 校验使能位
//1 = 所有CRC 无效的数据包都将被丢弃
//0 = 不考虑CRC 是否有效
//PMEN:格式匹配过滤器使能位
//当ANDOR = 1 时:
//1 = 数据包必须符合格式匹配条件,否则将被丢弃
//0 = 禁止过滤器
//当ANDOR = 0 时:
//1 = 符合格式匹配条件的数据包将被接受
//0 = 禁止过滤器
*/
ENC28J60_Write(ERXFCON,ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN|ERXFCON_BCEN);
ENC28J60_Write(EPMM0,0X3F);
ENC28J60_Write(EPMM1,0X30);
ENC28J60_Write(EPMCSL,0Xf9);
ENC28J60_Write(EPMCSH,0Xf7);
/*
//bit 0 MARXEN:MAC 接收使能位
//1 = 允许MAC 接收数据包
//0 = 禁止数据包接收
//bit 3 TXPAUS:暂停控制帧发送使能位
//1 = 允许MAC 发送暂停控制帧(用于全双工模式下的流量控制)
//0 = 禁止暂停帧发送
//bit 2 RXPAUS:暂停控制帧接收使能位
//1 = 当接收到暂停控制帧时,禁止发送(正常操作)
//0 = 忽略接收到的暂停控制帧
*/
ENC28J60_Write(MACON1,MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
//将MACON2 中的MARST 位清零,使MAC 退出复位状态。
ENC28J60_Write(MACON2,0x00);
/*
//bit 7-5 PADCFG2ACDFG0:自动填充和CRC 配置位
//111 = 用0 填充所有短帧至64 字节长,并追加一个有效的CRC
//110 = 不自动填充短帧
//101 = MAC 自动检测具有8100h 类型字段的VLAN 协议帧,并自动填充到64 字节长。如果不
//是VLAN 帧,则填充至60 字节长。填充后还要追加一个有效的CRC
//100 = 不自动填充短帧
//011 = 用0 填充所有短帧至64 字节长,并追加一个有效的CRC
//010 = 不自动填充短帧
//001 = 用0 填充所有短帧至60 字节长,并追加一个有效的CRC
//000 = 不自动填充短帧
//bit 4 TXCRCEN:发送CRC 使能位
//1 = 不管PADCFG如何,MAC都会在发送帧的末尾追加一个有效的CRC。 如果PADCFG规定要
//追加有效的CRC,则必须将TXCRCEN 置1。
//0 = MAC不会追加CRC。 检查最后4 个字节,如果不是有效的CRC 则报告给发送状态向量。
//bit 0 FULDPX:MAC 全双工使能位
//1 = MAC工作在全双工模式下。 PHCON1.PDPXMD 位必须置1。
//0 = MAC工作在半双工模式下。 PHCON1.PDPXMD 位必须清零。*/
ENC28J60_Write(MACON3,MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN|MACON3_FULDPX);
// 最大帧长度 1518
ENC28J60_Write(MAMXFLL,MAX_FRAMELEN&0XFF);
ENC28J60_Write(MAMXFLH,MAX_FRAMELEN>>8);
//配置背对背包间间隔寄存器MABBIPG。当使用
//全双工模式时,大多数应用使用15h 编程该寄存
//器,而使用半双工模式时则使用12h 进行编程。
ENC28J60_Write(MABBIPG,0x15);
//配置非背对背包间间隔寄存器的低字节
//MAIPGL。 大多数应用使用12h 编程该寄存器。
//如果使用半双工模式,应编程非背对背包间间隔
//寄存器的高字节MAIPGH。 大多数应用使用0Ch
//编程该寄存器。
ENC28J60_Write(MAIPGL,0x12);
ENC28J60_Write(MAIPGH,0x0C);
//设置MAC地址
ENC28J60_Write(MAADR5,enc28j60_dev.macaddr[0]);
ENC28J60_Write(MAADR4,enc28j60_dev.macaddr[1]);
ENC28J60_Write(MAADR3,enc28j60_dev.macaddr[2]);
ENC28J60_Write(MAADR2,enc28j60_dev.macaddr[3]);
ENC28J60_Write(MAADR1,enc28j60_dev.macaddr[4]);
ENC28J60_Write(MAADR0,enc28j60_dev.macaddr[5]);
//配置PHY为全双工 LEDB为拉电流
ENC28J60_PHY_Write(PHCON1,PHCON1_PDPXMD);
/*
//HDLDIS:PHY 半双工环回禁止位
//当PHCON1.PDPXMD = 1 或PHCON1.PLOOPBK = 1 时:
//此位可被忽略。
//当PHCON1.PDPXMD = 0 且PHCON1.PLOOPBK = 0 时:
//1 = 要发送的数据仅通过双绞线接口发出
//0 = 要发送的数据会环回到MAC 并通过双绞线接口发出*/
ENC28J60_PHY_Write(PHCON2,PHCON2_HDLDIS);
//ECON1 寄存器
//寄存器3-1 所示为ECON1 寄存器,它用于控制
//ENC28J60 的主要功能。 ECON1 中包含接收使能、发
//送请求、DMA 控制和存储区选择位。
ENC28J60_Set_Bank(ECON1);
/*
//EIE: 以太网中断允许寄存器
//bit 7 INTIE: 全局INT 中断允许位
//1 = 允许中断事件驱动INT 引脚
//0 = 禁止所有INT 引脚的活动(引脚始终被驱动为高电平)
//bit 6 PKTIE: 接收数据包待处理中断允许位
//1 = 允许接收数据包待处理中断
//0 = 禁止接收数据包待处理中断*/
ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,EIE,EIE_INTIE|EIE_PKTIE|EIE_TXIE|EIE_TXERIE|EIE_RXERIE);
/*
// enable packet reception
//bit 2 RXEN:接收使能位
//1 = 通过当前过滤器的数据包将被写入接收缓冲器
//0 = 忽略所有接收的数据包*/
ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,ECON1,ECON1_RXEN);
你自己对比一下吧。忘了那快了。反正改了初始化就好了。
一周热门 更多>