提出问题:
在调试单板网络通信的时候,发现:
1、打开上位机软件,并连续发送读取数据指令。
2、接上网络线,给单板供电,上位机软件能正确接收到数据;断开单板电源,重新给单板供电,上位机能正确接收到数据;频繁几次开关机测试,上位机依然能正确接收到数据。
3、在单板供电的情况下,带电插拔网络线,上位机能正确接收到数据。
4、断开网线,给单板供电,等待一段时间后,插上网络线;上位机无法接收到数据。频繁测试几次,每次上位机都无法接收到数据。
解决问题:
1、根据测试结果分析,先连接好网络线后给单板供电,网络通信正常;先给单板供电后接网络线,网络通信异常。
2、首先怀疑硬件的问题,开机的时候PHY芯片由于时序的问题没有启动;更换PHY芯片外围电阻,进行测试,问题依然没有解决。
3、排除硬件问题,考虑软件问题,借助IDE的调试功能模拟开机的过程;发现不接网络线给单板供电,网络接口无法启用;
4、逐步排查PHY芯片初始化过程,lwip协议初始化过程后,发现PHY芯片启动了自协商功能;在连接网络线的情况下,PHY芯片与PC机自动协商连接速度与工作模式;在没有网络线的情况下,自动协商功能超时,网络接口无法连接(link down)。
5、将自动协商功能关闭,并手动设置连接速度与工作模式,进行测试,通信正常;频繁几次测试后;通信依然正常。
延伸:
lwip协议都是抽象层,物理层的驱动需要依据不同的PHY芯片手动编写;然后在链接(link up)到lwip协议中。
lwip定义了通用的网络接口结构
struct netif{
struct netif *next;
#if LWIP_IPV4
ip_addr_t ip_addr; //IP地址
ip_addr_t ip_netmask; //子网掩码
ip_addr_t ip_gw; //默认网关
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
ip_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES];
ip_addr_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES];
#endif /* LWIP_IPV6 */
netif_input_fn input; //网络设备驱动调用,传递一个数据包到TCP/IP
#if LWIP_IPV4
netif_output_fn output; //发送数据包时,由IP模块调用。发送数据时,首先解析硬件地址然后发送数据。
//对以太网物理层,这个函数是etharp_output();
#endif
netif_linkoutput_fn linkoutput; //发送数据时,由etharp_out()函数调用
#if LWIP_IPV6
netif_output_ip6_fn output;
#end /* LWIP_IPV6 */
#if LWIP_NETIF_STATUS_CALLBACK
netif_status_callbcak_fn status_callbcak;
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBCAK
netif_status_calbcak_fn link_callbcak;
#endif /* LWIP_NETIF_LINK_CALLBCAK */
#if LWIP_NETIF_REMOVE_CALLBCAK
netif_status_callback_fn remove_callbcak;
#endif /* LWIP_NETIF_REMOVE_CALLBCAK */
void *state;
#ifdef netif_get_client_data
void* client_data[LWIP_NETIF_CLIENT_DATA_INDEX_MAX + LWIP_NUM_NETIF_CLIENT_DATA];
#endif
#if LWIP_IPV6_AUTOCONFIG
u8_t ip6_autoconfig_ebabled;
#enif
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
u8_t rs_count;
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
#if LWIP_NETIF_HOSTNAME
const char* hostname;
#endif /* LWIP_NETIF_HOSTNAME */
#if LWIP_CHECKSUM_CTRL_PER_NETIF
u16_t chksum_flag;
#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */
u16_t mtu; //最大发送字节数
u8_t hwaddr_len;
u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
u8_t flag;
char name[2];
u8_t num;
#if MIB2_STATS
u8_t link_type;
u32_t link_speed;
u32_t ts;
struct stats_mib2_netif_ctrs mib2_counters;
#endif /* MIB2_STATS */
#if LWIP_IPV4 && LWIP_IGMP
netif_igmp_mac_filter_fn igmp_mac_filter;
#endif /* LWIP_IPV4 && LWIP_IGMP */
#if LWIP_IPV6 && LWIP_IPV6_MLD
netif_mld_mac_filter_fn mld_mac_filter;
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
#if LWIP_NETIF_HWADDRHINT
u8_t *addr_hint;
#endif /* LWIP_NETIF_HWADDRHINT */
#if ENABLE_LOOPBACK
struct pbuf *loop_first;
struct pbuf *loop_last;
#if LWIP_LOOPBACK_MAX_PBUFS
u16_t loop_cnt_current;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
#endif /* ENABLE_LOOPBACK */
}