BabyOS增加第三方库LWIP
MCU项目中网络通讯是比较常用的功能,BabyOS选择增加LWIP为用户节省移植网络协议栈的时间,以及后续提供统一的网络操作接口。
目前硬件结构大概有两种:
网络数据流向:
整体来看,就是需要给LWIP提供以太网数据的发送接口,以及将收到的网络数据喂给LWIP。
BabyOS新增软件模块 b_mod_netif 用于LWIP与物理层的衔接。将MCU内部MAC控制器和MAC+PHY集成芯片都看作设备。通过bRead和bWrite读取和发送以太网数据。
这样有一个好处,例如这个场景:
第一版产品是STM32F107(带MAC控制器)+PHY芯片,后面更换为某国产MCU(没有MAC控制器),第二期产品使用 MCU+MAC/PHY集成芯片。只需要更换bNetif实例里面的设备号即可。
bNETIF_INSTANCE(bMcuNetif, bMCUMAC);
int main(void)
{
....
bInit();
bNetifAdd(&bMcuNetif, 0, 0, 0);
while (1)
{
bExec();
}
}
打开设备后会有一个操作:通过bCtl设置内存操作接口。为什么加上这个操作呢?
数据从驱动层到达Lwip大概有这么几个方式:
① 驱动层读取以太网数据,放在静态数组A。netif软件模块从驱动层读取数据放入struct pbuf结构的内存B。将B喂给LWIP。
② 驱动层读取以太网数据,放入动态内存A,netif软件模块从驱动层读取数据放入struct pbuf结构的内存B。将B喂给LWIP。
③ 驱动层读取以太网数据,放入 struct pbuf 结构的内存B,netif软件模块从驱动层获取B,喂给LWIP
方式①和②的内存峰值高,对于内存紧张的MCU来说不太友好。第3种方式不足就是让驱动层直接调用了lwip里面的接口,不太合理。
最终采用如下方式:
调用Lwip的接口放在b_mod_netif里面,给驱动层传入一个数据结构用于内存操作:
// 为了减少峰值内存,减少数据在不同层的拷贝。将上层操作struct pbuf的方法注册给下层使用
typedef struct
{
// m_create 申请空间
// len: 申请空间的长度
// p : 申请空间的指针
int (*m_create)(uint16_t len, void **p);
// m_next 申请的空间是链表形式,调用这个接口切换到下一块空间
// current_p: 指向当前使用的空间
// p : 得到的下一个空间的指针
int (*m_next)(void *current_p, void **p);
// m_payload 获取payload空间。
// p : 指向当前空间的指针
// payload: 空间可能存在头部,那么payload指向实际数据空间
// paylaod_len: 可用空间长度
int (*m_payload)(void *p, void **payload, uint32_t *payload_len);
} bHalBufList_t;
HAL层新增了b_hal_eth,用于适配带有MAC控制器的MCU。配合b_drv_mcumac驱动使用。
具体代码在dev分支,例程在例程仓库的hal_stm32f107分支。
TODO:
① 增加 MAC+PHY集成芯片的驱动。这样的芯片比较多,需要各位开发者一起添加。
② 增加 统一的网络接口,方便应用层使用。
有兴趣的开发者可以看看目前的代码,以及完成TODO事项。
如有建议和问题反馈,在这个ISSUE单下评论:https://gitee.com/notrynohigh/BabyOS/issues/I8L6R6