enc28j60 + UIP + STM32F103C6T6 电脑端接收数据错误,导致不能通讯问题

问题遇到的现象和发生背景

问题出现在arp阶段,MCU可以正常接收arp数,并且使用UIP解析正常,但是向电脑端响应arp请求时,通过Wireshark发现接收到的响应arp包数据格式不正常!

img

img

问题相关代码,请勿粘贴截图

        #define UIP_BUF ((struct uip_eth_hdr *)&uip_buf[0])

    tapdev_init();//初始化enc28j60
    print("init enc28j60 success!");
    uip_init();
    uip_ipaddr_t ipaddr;
    uip_ipaddr(ipaddr, 192, 168, 1, 8);
    uip_sethostaddr(ipaddr);
    uip_ipaddr(ipaddr, 192, 168, 1, 1);
    uip_setdraddr(ipaddr);
    uip_ipaddr(ipaddr, 255, 255, 252, 0);
    uip_setnetmask(ipaddr);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
        uip_len = tapdev_read();//uip_len在uip.c中声明
        if(uip_len == 0){
            continue;
        }
        print("ok");
        if(UIP_BUF->type == htons(UIP_ETHTYPE_ARP)) {
            uip_arp_arpin();
            if(uip_len>0){
                print("rarp package send!!!");
                print3((char*)uip_buf, uip_len);
                tapdev_send();
            }
        }
    /* USER CODE BEGIN 3 */
  }

tapdev.c 实现enc28j60收发代码:

#include <tapdev.h>
#include "enc28j60.h"
#include <uip.h>


//引用uip.c中声明的uip_ethaddr
extern struct uip_eth_addr uip_ethaddr;
//MAC
unsigned char my_mac[6] = {0x29, 0x7C, 0x07, 0x37, 0x24, 0x63};
void tapdev_init(void)
{
    enc28j60Init(my_mac);
    
     for (int i = 0; i < 6; i++)
     {
         uip_ethaddr.addr[i] = my_mac[i];
     }
}

unsigned int tapdev_read(void)
{
    enc28j60PacketReceive(MAX_FRAMELEN, uip_buf);
}


void tapdev_send(void)
{
    enc28j60PacketSend(uip_len, uip_buf);
}

更详细代码已上上传到蓝奏云,如果不愿下载,请评论通知我,我会尽快回复!
怀疑是用cubemx 生成代码时,SPI配置有问题,请帮忙确认, 非常感谢!

img

全部代码:
https://wwb.lanzouw.com/iNiJSxx0bah 密码:e5bk
使用cubemx + keil5

运行结果及报错内容
我的解答思路和尝试过的方法
我想要达到的结果

目前就想用uip ,实现电脑可以ping通的效果。
本人第一次使用SPI接口,非常希望各位能给一些解决办法的思路,非常感谢!

问题已解决,在调用驱动的写缓冲区操作(enc28j60WriteBuffer)时,写数据前,没有先执行写缓冲区命令,直接写入的数据,导致数据不正常:

void enc28j60WriteBuffer(unsigned int len, unsigned char* data)
    {
    ENC28J60_CSL();
    // issue write command
        /* 通过SPI发送写取缓冲区命令*/
    SPI1_ReadWrite(ENC28J60_WRITE_BUF_MEM);//没有调用这句
    
    while(len)
        {
        len--;
        SPI1_ReadWrite(*data);
        data++;
        }
    ENC28J60_CSH();
    }

遇见这种问题,如果想测试发送包是否正常,可以先手动调用enc28j60PacketSend(len, data)函数,比如调用enc28j60PacketSend发送0xAA,0xBB,0xCC十六进制数据,通过Wireshark拦截消息,看是否有接收到MCU发送数据包,并且发送数据包数据是否为0xAA,0xBB,0xCC.如果可以正常接收并且准确接收AA,BB,CC,表示驱动发送功能正常。
最后有些驱动函数名称有些区别,贴一下enc28j60PacketSend实现:

void enc28j60PacketSend(unsigned int len, unsigned char* packet)
    {
    // Set the write pointer to start of transmit buffer area
    enc28j60Write(EWRPTL, TXSTART_INIT&0xFF);
    enc28j60Write(EWRPTH, TXSTART_INIT>>8);

    // Set the TXND pointer to correspond to the packet size given
    enc28j60Write(ETXNDL, (TXSTART_INIT+len)&0xFF);
    enc28j60Write(ETXNDH, (TXSTART_INIT+len)>>8);

    // write per-packet control byte (0x00 means use macon3 settings)
    enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);

    // copy the packet into the transmit buffer
    enc28j60WriteBuffer(len, packet);

    // send the contents of the transmit buffer onto the network
    enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);

    // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
    if( (enc28j60Read(EIR) & EIR_TXERIF) )
        {
        enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
        }
    }

有关和enc28j60的一接线些信息,麻烦可以看一下上次提问的问题:
https://ask.csdn.net/questions/7608372?answer=53634904
上次中间加了一个路由器,这次是enc28j60直连电脑。正因为上次电脑和enc28j60中间有一个路由器,路由器拦截了错误格式的数据包,给我的现象是enc28j60没有发送数据,其实发送了,被路由器拦截了……
之前使用的协议栈好像不是官方写的,所以怀疑是代码的问题,所以换uip,但问题依旧,严重怀疑是在cubemx配置SPI配置的不对...
另外在ENC28J60说明书中,看到了接口的一些信息:

img

建议先测试一下ENC28J60的发送函数,感觉发出来的数据完全是乱的。

如果你怀疑SPI没有配置正确,可以把接收到的包用串口打印下来看看是否和wireshark里抓到的一致,如果一致,那SPI应该没有问题,接收过程,其实SPI是有读有写的。