关于nios的DM9000驱动中的中断嵌套问题

一,对上篇文档的补充说明

经过上次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的中断嵌套了。
  1. 在dm9000中断ISR中使用
    void Dm9000_ISR(void *context){
      int old_priority=alt_irq_interruptible(DM9000A_IF_0_IRQ);
      //isr中的其他操作
      alt_irq_non_interruptible(old_priority);
    }
    结果总是接收一段数据之后打印“ERROR”然后挂了。ERROR是ReceivePacket中打印的。改吧
  2. 修改结果
    <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,如有其它错误继续更新下一集!




菜鸟一枚,勿喷!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值