一,对上篇文档的补充说明
经过上次dm9000驱动的修改之后,可以正常的收发数据了,但是经过后期速度的测试发现传输速率有问题?而且会丢包?对于我这种菜鸟来说只能慢慢找了,靠想基本不可能。经过不断的测试发现,驱动的收发函数(ReceivePacket和TransmitPacket)中存在很多休眠usleep(20)。先去掉试试,发现收发数据没影响。哪看来去掉也无关紧要,至于那个驱动为什么要休眠,我懒得看手册了,毕竟dm9000也是个过时的东西!(借口)。回到正题,先测试下,pc给dm9000发送数据的结果,pc在10ms内发送给dm9000一包数据,数据长度大概65,总是会丢几包数据,后来发现我是在ReceivePacket之后一直检查还有没有数据要接收,如果有接收的就去接收,如果没有了,就检查数据包,然后dm9000或者网卡的机制是:ReceivePacket执行一次收到的是一个数据包,基本上就是一条网络协议。我应该在收到一包数据后立即去解析这包数据,然后再接收下一包。认识到这点后,立即修改了上篇文章!
二,先说nios中断事情吧
nios是支持中断嵌套的,但是默认进入一个中断后,如果中断ISR不返回的话,就算高优先级中断来了也是不会执行高优先级中断的。
在<bsp>/HAL/INC/priv/alt_legacy_irq.h中包含有ISR的API,其中有如下:
/*
* alt_irq_initerruptable() should only be called from within an ISR. It is used
* to allow higer priority interrupts to interrupt the current ISR. The input
* argument, "priority", is the priority, i.e. interrupt number of the current
* interrupt.
*
* If this function is called, then the ISR is required to make a call to
* alt_irq_non_interruptible() before returning. The input argument to
* alt_irq_non_interruptible() is the return value from alt_irq_interruptible().
*
* Care should be taken when using this pair of functions, since they increasing
* the system overhead associated with interrupt handling.
*
* If you are using an exception stack then nested interrupts won't work, so
* these functions are not available in that case.
*/
static ALT_INLINE alt_u32 ALT_ALWAYS_INLINE alt_irq_interruptible (alt_u32 priority)
{
extern volatile alt_u32 alt_priority_mask;
extern volatile alt_u32 alt_irq_active;
alt_u32 old_priority;
old_priority = alt_priority_mask;
alt_priority_mask = (1 << priority) - 1;
NIOS2_WRITE_IENABLE (alt_irq_active & alt_priority_mask);
NIOS2_WRITE_STATUS (1);
return old_priority;
}
/*
* See Comments above for alt_irq_interruptible() for an explanation of the use of this
* function.
*/
static ALT_INLINE void ALT_ALWAYS_INLINE alt_irq_non_interruptible (alt_u32 mask)
{
extern volatile alt_u32 alt_priority_mask;
extern volatile alt_u32 alt_irq_active;
NIOS2_WRITE_STATUS (0);
alt_priority_mask = mask;
NIOS2_WRITE_IENABLE (mask & alt_irq_active);
}
所以要实现中断嵌套,必须在DM9000_IF_0_IRQ的ISR中做如下操作
void Dm9000_ISR(void *context){
int old_priority=alt_irq_interruptible(DM9000A_IF_0_IRQ);
//isr中的其他操作
alt_irq_non_interruptible(old_priority);
}
三,我为什么要中断嵌套
在我的任务中,有一部分功能是nios是作为PC和FPGA的桥梁,即pc通过网络发的命令我要发给通过spi发给FPGA(为什么不用dma我不知道),FPGA通过DMA发给我的命令我要发给PC,在《一》中已经解决了网络丢包的问题了。然而后来测试发现我吧PC的数据发给了FPGA,而FPGA也得到了响应,即收到后将数据写入sdram然后产生一个中断,但是nios有时候在dm9000的中断中,是无法响应这个中断,所以只能实现nios的中断嵌套了。
- 在dm9000中断ISR中使用
结果总是接收一段数据之后打印“ERROR”然后挂了。ERROR是ReceivePacket中打印的。改吧void Dm9000_ISR(void *context){ int old_priority=alt_irq_interruptible(DM9000A_IF_0_IRQ); //isr中的其他操作 alt_irq_non_interruptible(old_priority); }
- 修改结果
<pre name="code" class="plain">void receivePcData(void *context) { int ret; unsigned int rx_len = 0; Communication *comm = (Communication*) context; unsigned short isr; isr = getISR(); //获取中断状态寄存器 clearISR(); //清除中断状态寄存器 disableInterrupt(); //禁用中断 if (isr & 0x01) //如果是接收中断 { if (comm->writeIndex >= comm->bufLength - 1) comm->writeIndex = 0; ret = ReceivePacket(comm->buf + comm->writeIndex, &rx_len); //接收数据包 comm->writeIndex += rx_len; int ret_v1=alt_irq_interruptible(DM9000A_IF_0_IRQ); analysisPacket(comm); alt_irq_non_interruptible(ret_v1); comm->writeIndex = 0; while (!ret) { ret = ReceivePacket(comm->buf + comm->writeIndex, &rx_len); comm->writeIndex += rx_len; int ret_v1=alt_irq_interruptible(DM9000A_IF_0_IRQ); analysisPacket(comm); alt_irq_non_interruptible(ret_v1); comm->writeIndex = 0; } } enableInterrupt(); }
终于测试通过,pc10ms一包数据,fpga一报数据大小256,没问题!ok,如有其它错误继续更新下一集!
菜鸟一枚,勿喷!