环境:
quartus11.0sp1,NIOSII 11.0IDE sp1(win7)
fpga开发板采用的是黑金开发板cyclone四代
nios2 eds自带ucos v286
lwip1.4.1
硬件部分:
ucos基本tmer:1ms interrupt
enc28j60相关设置:
spi设置:(10Mhz)
gpio:
LAN_nINT
LAN_nCS :简单output
LAN_nRST:简单output
软件部分:
enc28j60驱动参照linux内核驱动移植修改,这部分改动较多不一一描述:
enc28j60的初始化并使能接口函数
int enc28j60_net_open(void);//注意 开中断后调用此函数 不然有可能无法正常使用enc28j60
enc28j60中断处理函数
void enc28j60_irq_work_handler(void);// 注意 不要包含在中断函数中 需要退出中断后处理
enc28j60数据包发送函数
void enc28j60_packet_write(int len, const u8 *data);
spi驱动提供gpio驱动和spi驱动两种选择:
#define USE_SPICORE 1 // 1使用spicore , 0使用gpio
提供给enc28j60驱动调用函数:
int spi_write(unsigned char *buf, unsigned int len);
unsigned char spi_write_then_read(unsigned char *txbuf, int n_tx, unsigned char *rxbuf, int n_rx);
lwip移植参考焦海波移植手册,以及自带sys_arch.txt文档;
sys_arch.h:
/*
* sys_arch.h
*
* Created on: 2015-1-17
* Author: xw
*/
#ifndef SYS_ARCH_H_
#define SYS_ARCH_H_
/*********************************************************************************************************
* UCOS-II Port
*
* Target : Anyprocessor
* Put together by : Michael Anburaj
* URL : http://geocities.com/michaelanburaj/ Email : [email protected]
*
*********************************************************************************************************
*/
#include "os_cpu.h"
#include "os_cfg.h"
#ifndef OS_VERSION
#include "ucos_ii.h"
#endif /* OS_VERSION */
#include "system.h"
#define LWIP_MAX_TASKS OS_LOWEST_PRIO /* Number of LwIPtasks */
#define LWIP_START_PRIO 3 /* Defined the lowestLwIP task priority */
#ifndef LWIP_STACK_SIZE
#define LWIP_STACK_SIZE 2048
#endif /* LWIP_STACK_SIZE */
#define LWIP_COMPAT_MUTEX 1
/*#define LWIP_STACK_SIZE2048 Stack size for LwIP tasks */
/* Note:
Task priorities, LWIP_START_PRIO through(LWIP_START_PRIO+LWIP_MAX_TASKS-1) must be reserved
for LwIP and must not used by otherapplications outside. */
#define LWIP_Q_SIZE 10 /* LwIP queue size */
#define LWIP_MAX_QS 50 /* Max. LwIP queues */
#define SYS_MBOX_NULL NULL
#define SYS_SEM_NULL NULL
typedef struct {
OS_EVENT* pQ;
OS_EVENT* hMBox;
void* pvQEntries[LWIP_Q_SIZE];
} TQ_DESCR, *PQ_DESCR;
typedef OS_EVENT* sys_sem_t;
typedef PQ_DESCR sys_mbox_t;
typedef INT8U sys_thread_t;
#define T_LWIP_THREAD_START_PRIO 7
#define T_LWIP_THREAD_MAX_NB 1
#define T_LWIP_THREAD_STKSIZE 512
#endif /* __SYS_ARCH__H__ */
根据sys_arch.txt中需要实现的函数
/*
* sys_arch.c
*
* Created on: 2015-1-17
* Author: xw
*/
#include "arch/cc.h"
#include "arch/sys_arch.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "ucos_ii.h"
OS_STK T_LWIP_THREAD_STK[T_LWIP_THREAD_MAX_NB][T_LWIP_THREAD_STKSIZE];
static TQ_DESCR __staLwIPMBoxs[LWIP_MAX_QS];
PQ_DESCR pstCurFreeMBox;
//struct sys_timeouts {
//struct sys_timeout *next;
//};
//static struct sys_timeouts __staSysTimeouts[T_LWIP_THREAD_MAX_NB + 1];
u32_t sys_now(void){
return OSTime;
}
void sys_sem_signal(sys_sem_t *sem){
OSSemPost((OS_EVENT*)sem);
}
int sys_sem_valid(sys_sem_t *sem){
return (*sem != 0 ? 1 : 0);
//return OSSemAccept((OS_EVENT*)sem);
}
void sys_sem_free(sys_sem_t *sem){
INT8U res;
OSSemDel((OS_EVENT*)sem , OS_DEL_ALWAYS, &res);
}
err_t sys_sem_new(sys_sem_t *sem, u8_t count){
*sem = OSSemCreate (count);
return *sem ? 0 : -1;
}
void sys_sem_set_invalid(sys_sem_t *sem){
*sem = 0;
}
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout){
INT8U res;
OSSemPend((OS_EVENT*)sem, timeout, &res);
return res;
}
int sys_mbox_valid(sys_mbox_t *mbox){
return 0;
}
err_t sys_mbox_new(sys_mbox_t *mbox, int size){
mbox =(sys_mbox_t *) OSMboxCreate(&size);
return 0;
}
void sys_mbox_free(sys_mbox_t *mbox){
INT8U res;
OSMboxDel((OS_EVENT*)mbox, OS_DEL_ALWAYS, &res);
}
void sys_mbox_post(sys_mbox_t *mbox, void *msg){
OSMboxPost((OS_EVENT*)mbox, msg);
}
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg){
INT8U res;
res = OSMboxPost((OS_EVENT*)mbox, msg);
return res;
}
u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout){
INT8U res;
msg = OSMboxPend((OS_EVENT*)mbox, timeout, &res);
return res;
}
void sys_mbox_set_invalid(sys_mbox_t *mbox){
*mbox = 0;
}
u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg){
INT8U res;
msg = OSMboxPend((OS_EVENT*)mbox, 1, &res);
return res;
}
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio){
u8_t __ubPrio = 0;
//* 如果优先级定义没有超出系统允许的范围
if(prio > 0 && prio <= T_LWIP_THREAD_MAX_NB)
{
__ubPrio = T_LWIP_THREAD_START_PRIO + (prio - 1);
if(OS_NO_ERR ==
OSTaskCreate(thread,
arg,
&T_LWIP_THREAD_STK[prio-1][T_LWIP_THREAD_STKSIZE-1],
__ubPrio))
return __ubPrio;
}
return __ubPrio;
}
void sys_init(void){
u8_t i;
INT8U ucErr;
//* 先把数组清 0
//memset(__staLwIPMBoxs, 0, sizeof(__staLwIPMBoxs));
OSMemCreate((void*)__staLwIPMBoxs, LWIP_MAX_QS, sizeof(TQ_DESCR), &ucErr);
//* 建立链表和邮箱
for(i=0; i<(LWIP_MAX_QS-1); i++)
{
//* 把数组中的各成员链接在一起
__staLwIPMBoxs[i].pQ = &__staLwIPMBoxs[i+1];
//* 建立邮箱,系统必须保证邮箱能够顺利建立,如果出现错误,那是程序 BUG,
//* 应该在调试阶段排除
__staLwIPMBoxs[i].hMBox = OSQCreate(__staLwIPMBoxs[i].pvQEntries, LWIP_Q_SIZE);
}
//* 别忘了数组中最后一个元素,它还没有建立邮箱呢
__staLwIPMBoxs[LWIP_MAX_QS-1].hMBox = OSQCreate(__staLwIPMBoxs[LWIP_MAX_QS-1].pvQEntries, LWIP_Q_SIZE);
//* 保存链表首地址
pstCurFreeMBox = __staLwIPMBoxs;
//* 初始化 sys_timeouts 数组,将每个数组成员保存的链表地址设置为 NULL
//for(i=0; i
/*
* perf.h
*
* Created on: 2015-1-17
* Author: xw
*/
#ifndef PERF_H_
#define PERF_H_
#define PERF_START
#define PERF_STOP(x)
#endif /* PERF_H_ */
/*
* cc.h
*
* Created on: 2015-1-17
* Author: xw
*/
#ifndef CC_H_
#define CC_H_
/* FPAG-NIOS platform*/
#include"errno.h" //定义错误编码
#include "alt_types.h" //定义NIOS数据类型
//#include "lwipopts.h" //
#define BYTE_ORDER LITTLE_ENDIAN //字的高低位顺序
//数据长度
typedef alt_u8 u8_t; //一个无符号字节类型, 8bits 0~~255
typedef alt_8 s8_t; //一个有符号字节类型, 8 bits -127~~-127
typedef alt_u16 u16_t; //一个无符号字(=2个字节)类型,16 bits
typedef alt_16 s16_t; //一个有符号字(=2个字节)类型,16 bits
typedef alt_u32 u32_t; //一个无符号字节类型, 32 bits
typedef alt_32 s32_t; //一个有符号字节类型, 32 bits
typedef u32_t mem_ptr_t; //
#include
/* Plaform specific diagnostic output 与平台相关的调试输出 */
#define LWIP_PLATFORM_DIAG(x) {printf x;}
#define LWIP_PLATFORM_ASSERT(x) {printf("Assertion\"%s\" failed at line %d in %s\n", x, __LINE__, __FILE__); while(1);}
//编译器对c语言中struct结构字节对齐
#define PACK_STRUCT_FIELD(x) x __attribute__((packed))
#define PACK_STRUCT_STRUCT __attribute__((packed))
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_END
#endif /* CC_H_ */
选择nios eds程序优化选项optimization level:level 3 否则数据处理延时很长
mian.c建立任务初始化lwip:
IP4_ADDR(&my_gw, 192,168,1,1);
IP4_ADDR(&my_ipaddr, 192,168,1,6);
IP4_ADDR(&my_netmask, 255,255,255,0);
//printf("Hello LWIP!\n");
lwip_init();
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(LAN_NINT_BASE, 1);//允许irq接受
alt_ic_isr_register(LAN_NINT_IRQ_INTERRUPT_CONTROLLER_ID, LAN_NINT_IRQ ,(void *)enc28j60_irq,NULL,NULL);
#if NO_SYS
netif_add(&my_netif, &my_ipaddr, &my_netmask, &my_gw, NULL, netif_loopif_init, ip_input);
#else /* NO_SYS */
netif_add(&my_netif, &my_ipaddr, &my_netmask, &my_gw, NULL, ethernetif_init, ethernet_input);
#endif /* NO_SYS */
netif_set_default(&my_netif);
printf("netif_set_up!\n");
netif_set_up(&my_netif);
测试ping命令结果:
经过大概一周的努力终于可以使用lwip了,还是存在不少问题,已发现问题如下:
1、通信速度,udp包最大发送速度在15kbyte/s (不用ucos,nios裸机测试也是这个速度)
2、udp、tcp、ping 数据包大小最大500字节 如果遇到大于500字节的数据包nios死机 (这个问题应该可以通过opt.h定义修改)
3、nios持续不断的已最大速度发送udp数据包几分钟内死机
4、ping命令几个小时保持正常,但反应速度慢 最快也要2ms
quartus工程和nios工程下载:http://download.csdn.net/detail/yoeksome/8404853