ARM硬件平台上基于UCOS移植Lwip网络协议栈
OSQFlush(mbox->ucos_queue);
OSQDel(mbox->ucos_queue, OS_DEL_ALWAYS, &Err);
OSMemPut( MboxMem, mbox );
}
实现void sys_mbox_post(sys_mbox_t mbox, void *msg)函数功能:
void sys_mbox_post(sys_mbox_t mbox, void *msg)
{
if (msg == NULL)
msg = (void*)&NullMessage;//解决空指针投递的问题
while (OSQPost(mbox->ucos_queue, msg) == OS_Q_FULL)
OSTimeDly(10);
}
实现u32_t
sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)函数:
u32_t
sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
{
u8_t Err;
u32_t wait_ticks;
void *Data;
Data = OSQAccept(mbox->ucos_queue);
if (Data != NULL)
{
if (Data == (void*)&NullMessage)
{
*msg = NULL;
}
else
{
*msg = Data;
}
return 0;
}
wait_ticks = 0;
if(timeout!=0){
wait_ticks = (timeout * OS_TICKS_PER_SEC)/1000;
if(wait_ticks < 1)
wait_ticks = 1;
else if(wait_ticks > 65535)
wait_ticks = 65535;
}
Data = OSQPend(mbox->ucos_queue, (u16_t)wait_ticks, &Err);
if (Data != NULL)
{
if (Data == (void*)&NullMessage)
{
*msg = NULL;
}
else
{
*msg = Data;
}
}
if (Err == OS_NO_ERR)
return timeout/2; //将等待时间设置为timeout/2
else
return SYS_ARCH_TIMEOUT;
}
实现struct sys_timeouts * sys_arch_timeouts(void)函数功能:
struct sys_timeouts * sys_arch_timeouts(void)
{
return &global_timeouts;
}
实现sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)函数功能:
sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
{
static u32_t TaskCreateFlag=0;
u8_t i=0;
name=name;
stacksize=stacksize;
while((TaskCreateFlag>>i)&0x01){
if(i
else return 0;
}
if(OSTaskCreate(thread,(void*)arg, &LWIP_STK_AREA[i][LWIP_STK_SIZE-1],prio)==OS_NO_ERR){
TaskCreateFlag |=(0x01};
return prio;
}
新建一个进程,在整个系统中只会被调用一次。
移植操作系统模拟层完成。
4.4 根据lwip提供的软件架构编写相应的网卡芯片驱动
从用户编程角度看,针对RTL8019AS的操作实际上就是对RTL8019AS内部寄存器的操作,以实现网卡的初始化、数据发送、数据接收等操作。发送数据时,主控制器将数据写入网卡的SRAM中,然后发送一个发送数据指令,网卡就会将数据封装成标准以太网物理层数据帧发送出去。同理,网卡接收到以太网数据时,网卡会自动解析成高层使用的有效格式,放在内部SRAM中供主控芯片读取,我们采用周期查询方式实现接收数据的处理。
RTL8019AS与主控芯片间通讯的输入/输出地址共有32个,地址偏移量为00H-1FH。其中00-0F共16个地址,为内部寄存器地址,RTL8019AS的内部寄存器每个都是8位的,所有寄存器一共分为4页,每一页都共享这16个偏移量,当前那一页有效是由CR寄存器的值决定的。
要接收和发送数据包都必须读写网卡的内部的16k的ram,必须通过DMA进行读和写.网卡的内部ram是一块双端口的16k字节的ram.所谓双端口就是说有两套总线连结到该ram,一套总线A是网卡控制器读/写网卡上的ram,另一套总线B是主控制器读/写网卡上的ram.总线A又叫Local DMA,总线B又叫Remote DMA.
远程DMA地址包括10H~17H,都可以用来做远程DMA端口,只要用其中的一个就可以了。我们使用10H。
复位端口包括18H~1FH共8个地址,功能一样,用于RTL8019AS复位。我们使用18H。
Lwip提供了网卡驱动框架形式,我们只要根据实际使用的网卡特性完善这些函数就可以了。
具体说我们应该实现以5个函数的实现。
static void low_level_init(struct netif *netif)。
static err_t low_level_output(struct netif *netif, struct pbuf *p)
static struct pbuf *low_level_input(struct netif *netif)
err_t ethernetif_init(struct netif *netif)
static void ethernetif_input(struct netif *netif)
前3个函数与网卡驱动函数密切相关。low_level_init为网卡初始化函数,主要用来完成网卡的复位及参数初始化。low_level_output为网卡数据包发送函数。low_level_input为网卡数据包接收函数。
ethernetif_input函数主要作用是调用网卡数据包接收函数low_level_input从网卡SRAM中读取一个数据包,然后解析数据包类型,然后交付给上层应用程序。实际上,ethernetif_input已经是一个可以直接使用的函数,调用一次可以完成数据包的接收和递交。我们在应用层建立一个任务周期性调用该函数实现接收数据包的功能。
ethernetif_init是上层应用在管理网络接口结构netif时调用的函数。该函数主要完成netif结构中的某些字段初始化,并最终调用low_level_init函数完成网卡的初始化。
low_level_init函数实现源代码:
static void
low_level_init(struct netif *netif)
{
struct ethernetif *ethernetif = netif->state;
ARM硬件平台UCOS移植网络协议 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)