1. bread88lifa利发国际娱乐论坛/
  2. 嵌入式论坛/
    1. 电子论坛综合区
    2. 嵌入式论坛
    3. 电源技术论坛
    4. 硬件设计论坛
    5. 测试测量论坛
    6. 检测技术与质量
    7. EDA设计论坛
    8. 综合技术与应用
    9. 开源硬件
    10. IC设计论坛
    11. 消费电子论坛
    12. 无线通信论坛
    13. 个人版区
    14. 厂商专区
    15. 论坛服务区
    16. 高校联盟
    17. 供求信息发布
  3. 嵌入式系统论坛
    1. ARM技术论坛
    2. Android论坛
    3. Linux论坛
    4. 单片机/MCU论坛
    5. FPGA|CPLD|ASIC论坛
    6. DSP论坛
  4. / 第21章 RL-TCPnet之高效的事件触发框架
    关闭提示
12下一页

[经验] 第21章 RL-TCPnet之高效的事件触发框架

[复制链接]
版主
发表于 2017-11-14 09:15:49   451 查看 36 回复 只看该作者 倒序浏览
分享
转最新网络教程
本章节为大家讲解高效的事件触发框架实现方法,BSD Socket编程和后面章节要讲解到的FTP、TFTP和HTTP等都非常适合使用这种方式。实际项目中也推荐大家采用这种方式,不过仅适用于RTOS环境,比如RTX、FreeRTOS或者uCOS-III均可,裸机方式不支持。
        另外,前面章节讲解的TCP和UDP的原始socket使用这种方式不太方便,因为应用程序的编写会变的稍麻烦,不像BSD Socket那么省事。
21.1 初学者重要提示
21.2 高效的事件触发框架说明
21.3 RTX系统实例修改方法
21.4 uCOS-III系统实例修改方法
21.5 FreeRTOS系统实例修改方法
21.6 实验操作和实验例程说明
21.7      总结
版主
发表于 2017-11-22 09:33:06    楼主|
21.1  初学者重要提示

1、实际项目中强烈推荐大家采用这种方式,不过仅适用于RTOS环境,比如RTX、FreeRTOS或者uCOS-III均可。后面章节配套的例子,基本也都采用这种方式。
2、前面章节讲解的TCP和UDP的原始socket使用这种方式不太方便,因为应用程序的编写会变的稍麻烦,不像BSD Socket这么省事。
回复 点赞 举报
版主
发表于 2017-11-23 08:21:02    楼主|
21.2  高效的事件触发框架说明


        讲解高效的事件触发框架之前,先看下没有使用事件触发方式时,ping的响应速度,以例程:V6-1024_RL-TCPnet实验_BSD Socket服务器之TCP(RTX)为例进行说明:

回复 点赞 举报
版主
发表于 2017-11-23 08:21:50    楼主|
下面是使用了事件触发方式时,ping的响应速度,以例程:V6-1030_RL-TCPnet实验_高效的事件触发框架(RTX)为例进行说明:


从上面的两个响应速度的对比中,可以看出,使用了时间触发方式的例子,响应速度都在1ms以下,效果还是非常明显的。
回复 点赞 举报
版主
发表于 2017-11-23 08:22:12    楼主|
前面章节配套的例子里面,响应速度慢,是因为我们都是周期性的调用RL-TCPnet的主处理函数main_TcpNet(),比如前面BSD Socket服务器章节配套的例子中:
/*
*********************************************************************************************************
*    函 数 名: AppTaskTCPMain
*    功能说明: RL-TCPnet网络主任务
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 5
*********************************************************************************************************
*/
__task void AppTaskTCPMain(void)
{
     while (1)
     {
         /* RL-TCPnet处理函数 */
         main_TcpNet();
         os_dly_wait(2);
     }
}
回复 点赞 举报
版主
发表于 2017-11-23 08:22:28    楼主|
这种方式有如下两个缺点:
1、没有网络通信时也要周期性的执行。
2、实时响应差,因为在延迟的这段时间内有网络数据包的话,数据包得不到及时的处理。
        另外特别注意一点,一些不理解的读者会问,我们的底层函数里面不是有以太网中断吗,为什么还会不能实时性响应呢?根本的原因就在,虽然有以太网中断,但是中断后,RL-TCPent的主处理函数main_TcpNet()不能得到及时的执行,所以我们要解决的就是让主处理函数得到实时执行。
        用户通过修改以下几个地方就可以实现:
1、修改ETH_STM32F4xx.c文件中的函数send_frame。
2、修改ETH_STM32F4xx.c文件中的以太网中断函数。
3、修改RL-TCPnet的时间基准更新任务。
4、修改RL-TCPnet的网络主任务,函数main_TcpNet的调用不再采用轮询方式,改成事件标志等待方式。
        下面针对RTX、uCOS-III和FreeRTOS操作系统分别做讲解:
回复 点赞 举报
版主
发表于 2017-11-23 08:22:45    楼主|
21.3 RTX系统实例修改方法


        下面针对RTX系统要做的具体修改做个说明,我们以例程:V6-1024_RL-TCPnet实验_BSD Socket服务器之TCP(RTX)为例。通过修改函数send_frame,以太网中断和时间基准更新任务都给网络主任务发事件标志,让其得到实时执行,从而实现高效的事件触发框架。
回复 点赞 举报
版主
发表于 2017-11-23 08:23:00    楼主|
21.3.1 修改函数send_frame


        修改ETH_STM32F4xx.c文件中的函数send_frame,此函数的末尾添加事件标志函数os_evt_set(0x0001, HandleTaskTCPMain);
/*
*********************************************************************************************************
*    函 数 名: send_frame
*    功能说明: 传递数据帧给MAC DMA发送描述符,并使能发送。
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
extern OS_TID HandleTaskTCPMain;
void send_frame (OS_FRAME *frame)
{
     U32 *sp,*dp;
     U32 i,j;

     j = TxBufIndex;
    
     /* 等待上一帧数据发送完成 */
     while (Tx_Desc[j].CtrlStat & DMA_TX_OWN);

     sp = (U32 *)&frame->data[0];
     dp = (U32 *)(Tx_Desc[j].Addr & ~3);

     /* 复制要发送的数据到DMA发送描述符中 */
     for (i = (frame->length + 3) >> 2; i; i--)
     {
         *dp++ = *sp++;
     }
    
     /* 设置数据帧大小 */
     Tx_Desc[j].Size      = frame->length;
    
     /* 发送描述符由DMA控制发送 */
     Tx_Desc[j].CtrlStat |= DMA_TX_OWN;
    
     if (++j == NUM_TX_BUF) j = 0;
     TxBufIndex = j;
    
     /* 开始帧传输 */
     /*
        DMASR 以太网 DMA 状态寄存器
        向ETH_DMASR寄存器[16:0]中的(未保留)位写入1会将其清零,写入 0 则不起作用。
        位1 TPSS:发送过程停止状态 (Transmit process stopped status)
                 当发送停止时,此位置 1。
     */
     ETH->DMASR   = DSR_TPSS;
    
     /*
        DMATPDR 以太网DMA发送轮询请求寄存器
       应用程序使用此寄存器来指示DMA轮询发送描述符列表。
       位 31:0 TPD:发送轮询请求(Transmit poll demand)
                    向这些位写入任何值时,DMA都会读取ETH_DMACHTDR寄存器指向的当前描述符。如果
                    该描述符不可用(由CPU所有),则发送会返回到挂起状态,并将ETH_DMASR寄存器位2
                    进行置位。如果该描述符可用,则发送会继续进行。      
     */
     ETH->DMATPDR = 0;
    
     os_evt_set(0x0001, HandleTaskTCPMain);
}
回复 点赞 举报
版主
发表于 2017-11-23 08:23:19    楼主|
21.3.2 修改以太网中断函数


        修改ETH_STM32F4xx.c文件中的以太网中断函数,此函数的末尾添加事件标志函数:isr_evt_set(0x0001, HandleTaskTCPMain);
/*
*********************************************************************************************************
*    函 数 名: ETH_IRQHandler
*    功能说明: 以太网中断,主要处理从MAC DMA接收描述符接收到的数据帧以及错误标志的处理。
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void ETH_IRQHandler (void)
{
     OS_FRAME *frame;
     U32 i, RxLen;
     U32 *sp,*dp;

     i = RxBufIndex;
    
     /* 循环所有接受描述符列表,遇到未接收到数据的退出循环 */
     do
     {
         /*
              #define DMA_RX_ERROR_MASK   (DMA_RX_ES | DMA_RX_LE | DMA_RX_RWT | \
                                              DMA_RX_RE | DMA_RX_CE)
            
              有错误,放弃此帧数据,错误类型包含如下:
              位15 DMA_RX_ES:错误汇总(Error summary),即CRC错误,接收错误,看门狗超时,延迟冲突等。
             位12 DMA_RX_LE:长度错误(Length error)
                             该位置1时,指示接收帧的实际长度与长度/类型字段的值不符。该字段仅在帧类
                             型位(RDES0[5])复位后有效。
              位4 DMA_RX_RWT:接收看门狗超时 (Receive watchdog timeout)
                             该位置1时,表示接收看门狗计时器在接收当前帧时超时,且当前帧在看门狗超
                             时后被截断了
              位3 DMA_RX_RE: 接收错误 (Receive error)
                            该位置1时,表示在帧接收期间,当发出RX_DV信号时,会发出RX_ERR信号。
              位1 DMA_RX_CE: CRC 错误(CRC error)
                            该位置1时,表示接收的帧发生循环冗余校验(CRC)错误。只有最后一个描述符
                             (RDES0[8])置1时,该字段才有效
         */
         if (Rx_Desc[i].Stat & DMA_RX_ERROR_MASK)
         {
              goto rel;
         }
        
          /*
              #define DMA_RX_SEG_MASK   (DMA_RX_FS | DMA_RX_LS)
             位9 FS:第一个描述符 (First descriptor)
                    该位置1时,指示此描述符包含帧的第一个缓冲区。如果第一个缓冲区的大小为0,则第二
                    个缓冲区将包含帧的帧头。如果第二个缓冲区的大小为0,则下一个描述符将包含帧的帧头。
        
             位8 LS:最后一个描述符 (Last descriptor)
                    该位置1时,指示此描述符指向的缓冲区为帧的最后一个缓冲区。
        
             下面的函数用于判断此帧数据是否只有一个缓冲,初始化接收描述符列表的时候,每个描述符仅设置了
             一个缓冲。
         */
         if ((Rx_Desc[i].Stat & DMA_RX_SEG_MASK) != DMA_RX_SEG_MASK)
         {
              goto rel;
         }
        
         RxLen = ((Rx_Desc[i].Stat >> 16) & 0x3FFF) - 4;
         if (RxLen > ETH_MTU)
         {
              /* 数据包太大,直接放弃 */
              goto rel;
         }
        
          /* 申请动态内存,RxLen或上0x80000000表示动态内存不足了不会调用函数sys_error() */
         frame = alloc_mem (RxLen | 0x80000000);
        
          /* 如果动态内存申请失败了,放弃此帧数据;成功了,通过函数put_in_queue存入队列中 */
         if (frame != NULL)
         {
              sp = (U32 *)(Rx_Desc[i].Addr & ~3);
              dp = (U32 *)&frame->data[0];
              for (RxLen = (RxLen + 3) >> 2; RxLen; RxLen--)
              {
                   *dp++ = *sp++;
              }
              put_in_queue (frame);
         }
        
          /* 设置此接收描述符继续接收新的数据 */
         rel: Rx_Desc[i].Stat = DMA_RX_OWN;

         if (++i == NUM_RX_BUF) i = 0;
     }
     while (!(Rx_Desc[i].Stat & DMA_RX_OWN));
    
     RxBufIndex = i;

     /*
        DMASR DMA的状态寄存器(DMA status register)
        位7 RBUS:接收缓冲区不可用状态 (Receive buffer unavailable status)
                 此位指示接收列表中的下一个描述符由CPU所拥有,DMA无法获取。接收过程进入挂起状态。
                  要恢复处理接收描述符,CPU应更改描述符的拥有关系,然后发出接收轮询请求命令。如果
                  未发出接收轮询请求命令,则当接收到下一个识别的传入帧时,接收过程会恢复。仅当上一
                  接收描述符由DMA所拥有时,才能将ETH_DMASR[7]置1。
    
        DMAIER的接收缓冲区不可用中断RBUIE是bit7,对于的接收缓冲区不可用状态在DMA状态寄存器中也是bit7。
     */
     if (ETH->DMASR & INT_RBUIE)
     {
         /* 接收缓冲区不可用,重新恢复DMA传输 */
         ETH->DMASR = ETH_DMASR_RBUS;
         ETH->DMARPDR = 0;
     }
    
     /*
        DMASR DMA的状态寄存器(DMA status register)
        这里实现清除中断挂起标志
        位16 ETH_DMASR_NIS:所有正常中断 (Normal interrupt summary)
        位15 ETH_DMASR_AIS:所有异常中断 (Abnormal interrupt summary)
        位6  ETH_DMASR_RS :接收状态 (Receive status)
                            此位指示帧接收已完成,具体的帧状态信息已经包含在描述符中,接收仍保持运行状态。
     */
     ETH->DMASR = ETH_DMASR_NIS | ETH_DMASR_AIS | ETH_DMASR_RS;
    
     isr_evt_set(0x0001, HandleTaskTCPMain);
}
回复 点赞 举报
版主
发表于 2017-11-23 08:23:40    楼主|
21.3.3 修改RL-TCPnet的时间基准更新任务


        修改RL-TCPnet的时间基准更新任务,添加事件标志函数os_evt_set(0x0001, HandleTaskTCPMain);
/*
*********************************************************************************************************
*    函 数 名: AppTaskStart
*    功能说明: 启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 6
*********************************************************************************************************
*/
__task void AppTaskStart(void)
{
     /* 初始化RL-TCPnet */
     init_TcpNet ();
    
     /* 创建任务 */
     AppTaskCreate();
    
     os_itv_set (100);
    
    while(1)
    {
         os_itv_wait ();
        
         /* RL-TCPnet时间基准更新函数 */
          timer_tick ();
         os_evt_set(0x0001, HandleTaskTCPMain);
    }
}
回复 点赞 举报
版主
发表于 2017-11-23 08:23:55    楼主|
21.3.4 修改RL-TCPnet的网络主任务


        修改RL-TCPnet的网络主任务,函数main_TcpNet的调用不再采用轮询方式,改成事件标志等待方式,即修改为如下形式:
/*
*********************************************************************************************************
*    函 数 名: AppTaskTCPMain
*    功能说明: RL-TCPnet网络主任务
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 5
*********************************************************************************************************
*/
__task void AppTaskTCPMain(void)
{
     while (1)
     {
          /* RL-TCPnet处理函数 */
         os_evt_wait_and(0x0001, 0xFFFF);
         while (main_TcpNet() == __TRUE);
     }
}
回复 点赞 举报
版主
发表于 2017-11-23 08:24:14    楼主|
21.3.5 最后特别注意优先级安排


        最后,用户要特别注意几个任务的优先级安排,非常重要。
1、RL-TCPnet的时间基准更新任务一定要是最高优先级任务。
2、RL-TCPnet的网络主任务,即调用函数main_TcpNet的任务是次高优先级任务。
3、应用层的任务要比前面两个任务的优先级都低。
回复 点赞 举报
版主
发表于 2017-11-23 08:24:29    楼主|
21.4 uCOS-III系统实例修改方法


        下面针对uCOS-III系统要做的具体修改做个说明,我们以例程:V6-1025_RL-TCPnet实验_BSD Socket服务器之TCP(uCOS-III)为例。通过修改函数send_frame,以太网中断和时间基准更新任务都给网络主任务发事件标志,让其得到实时执行,从而实现高效的事件触发框架。
回复 点赞 举报
版主
发表于 2017-11-23 08:24:45    楼主|
21.4.1 创建事件标志组


        创建uCOS-III的事件标志组:
OS_FLAG_GRP        FLAG_TCPnet;

/*
*********************************************************************************************************
*    函 数 名: AppObjCreate
*    功能说明: 创建任务通讯
*    形    参: p_arg 是在创建该任务时传递的形参
*    返 回 值: 无
*********************************************************************************************************
*/
static  void  AppObjCreate (void)
{
     OS_ERR      err;
    
     /* 创建事件标志组 */
     OSFlagCreate ((OS_FLAG_GRP  *)&FLAG_TCPnet,
                  (CPU_CHAR     *)"FLAG TCPnet",
                  (OS_FLAGS      )0,
                  (OS_ERR       *)&err);
}
回复 点赞 举报
版主
发表于 2017-11-23 08:25:03    楼主|
21.4.2 修改函数send_frame


         修改ETH_STM32F4xx.c文件中的函数send_frame,此函数的末尾添加事件标志函数OSFlagPost(宏定义uCOS_EN在bsp.h文件里面使能,针对教程配套例子做的定义,方便管理。大家自己搞时,不必受此限制)。
/*
*********************************************************************************************************
*    函 数 名: send_frame
*    功能说明: 传递数据帧给MAC DMA发送描述符,并使能发送。
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void send_frame (OS_FRAME *frame)
{
     U32 *sp,*dp;
     U32 i,j;

#if uCOS_EN == 1
     OS_ERR  err;
#endif

     j = TxBufIndex;
    
     /* 等待上一帧数据发送完成 */
     while (Tx_Desc[j].CtrlStat & DMA_TX_OWN);

     sp = (U32 *)&frame->data[0];
     dp = (U32 *)(Tx_Desc[j].Addr & ~3);

     /* 复制要发送的数据到DMA发送描述符中 */
     for (i = (frame->length + 3) >> 2; i; i--)
     {
         *dp++ = *sp++;
     }
    
     /* 设置数据帧大小 */
     Tx_Desc[j].Size      = frame->length;
    
     /* 发送描述符由DMA控制发送 */
     Tx_Desc[j].CtrlStat |= DMA_TX_OWN;
    
     if (++j == NUM_TX_BUF) j = 0;
     TxBufIndex = j;
    
     /* 开始帧传输 */
     /*
        DMASR 以太网 DMA 状态寄存器
        向ETH_DMASR寄存器[16:0]中的(未保留)位写入1会将其清零,写入 0 则不起作用。
        位1 TPSS:发送过程停止状态 (Transmit process stopped status)
                 当发送停止时,此位置 1。
     */
     ETH->DMASR   = DSR_TPSS;
    
     /*
        DMATPDR 以太网DMA发送轮询请求寄存器
       应用程序使用此寄存器来指示DMA轮询发送描述符列表。
       位 31:0 TPD:发送轮询请求(Transmit poll demand)
                    向这些位写入任何值时,DMA都会读取ETH_DMACHTDR寄存器指向的当前描述符。如果
                    该描述符不可用(由CPU所有),则发送会返回到挂起状态,并将ETH_DMASR寄存器位2
                    进行置位。如果该描述符可用,则发送会继续进行。      
     */
     ETH->DMATPDR = 0;
    
#if uCOS_EN == 1
     OSFlagPost ((OS_FLAG_GRP  *)&FLAG_TCPnet,
                   (OS_FLAGS      )0x0001,
                   (OS_OPT        )OS_OPT_POST_FLAG_SET,
                   (OS_ERR       *)&err);
#endif  
}
回复 点赞 举报
版主
发表于 2017-11-23 08:25:21    楼主|
21.4.3 修改以太网中断函数


        修改ETH_STM32F4xx.c文件中的以太网中断函数,此函数的末尾添加事件标志函数:OSFlagPost(宏定义uCOS_EN在bsp.h文件里面使能,针对教程配套例子做的定义,方便管理。大家自己搞时,不必受此限制)。
/*
*********************************************************************************************************
*    函 数 名: ETH_IRQHandler
*    功能说明: 以太网中断,主要处理从MAC DMA接收描述符接收到的数据帧以及错误标志的处理。
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void ETH_IRQHandler (void)
{
     OS_FRAME *frame;
     U32 i, RxLen;
     U32 *sp,*dp;

#if uCOS_EN == 1
     OS_ERR  err;
     CPU_SR_ALLOC();

     CPU_CRITICAL_ENTER();
     OSIntEnter();                        
     CPU_CRITICAL_EXIT();
#endif

     i = RxBufIndex;
    
     /* 循环所有接受描述符列表,遇到未接收到数据的退出循环 */
     do
     {
         /*
              #define DMA_RX_ERROR_MASK   (DMA_RX_ES | DMA_RX_LE | DMA_RX_RWT | \
                                              DMA_RX_RE | DMA_RX_CE)
            
              有错误,放弃此帧数据,错误类型包含如下:
              位15 DMA_RX_ES:错误汇总(Error summary),即CRC错误,接收错误,看门狗超时,延迟冲突等。
             位12 DMA_RX_LE:长度错误(Length error)
                             该位置1时,指示接收帧的实际长度与长度/类型字段的值不符。该字段仅在帧类
                             型位(RDES0[5])复位后有效。
              位4 DMA_RX_RWT:接收看门狗超时 (Receive watchdog timeout)
                             该位置1时,表示接收看门狗计时器在接收当前帧时超时,且当前帧在看门狗超
                             时后被截断了
              位3 DMA_RX_RE: 接收错误 (Receive error)
                            该位置1时,表示在帧接收期间,当发出RX_DV信号时,会发出RX_ERR信号。
              位1 DMA_RX_CE: CRC 错误(CRC error)
                            该位置1时,表示接收的帧发生循环冗余校验(CRC)错误。只有最后一个描述符
                             (RDES0[8])置1时,该字段才有效
         */
         if (Rx_Desc[i].Stat & DMA_RX_ERROR_MASK)
         {
              goto rel;
         }
        
          /*
              #define DMA_RX_SEG_MASK   (DMA_RX_FS | DMA_RX_LS)
             位9 FS:第一个描述符 (First descriptor)
                    该位置1时,指示此描述符包含帧的第一个缓冲区。如果第一个缓冲区的大小为0,则第二
                    个缓冲区将包含帧的帧头。如果第二个缓冲区的大小为0,则下一个描述符将包含帧的帧头。
        
             位8 LS:最后一个描述符 (Last descriptor)
                    该位置1时,指示此描述符指向的缓冲区为帧的最后一个缓冲区。
        
             下面的函数用于判断此帧数据是否只有一个缓冲,初始化接收描述符列表的时候,每个描述符仅设置了
             一个缓冲。
         */
         if ((Rx_Desc[i].Stat & DMA_RX_SEG_MASK) != DMA_RX_SEG_MASK)
         {
              goto rel;
         }
        
         RxLen = ((Rx_Desc[i].Stat >> 16) & 0x3FFF) - 4;
         if (RxLen > ETH_MTU)
         {
              /* 数据包太大,直接放弃 */
              goto rel;
         }
        
          /* 申请动态内存,RxLen或上0x80000000表示动态内存不足了不会调用函数sys_error() */
         frame = alloc_mem (RxLen | 0x80000000);
        
          /* 如果动态内存申请失败了,放弃此帧数据;成功了,通过函数put_in_queue存入队列中 */
         if (frame != NULL)
         {
              sp = (U32 *)(Rx_Desc[i].Addr & ~3);
              dp = (U32 *)&frame->data[0];
              for (RxLen = (RxLen + 3) >> 2; RxLen; RxLen--)
              {
                   *dp++ = *sp++;
              }
              put_in_queue (frame);
         }
        
          /* 设置此接收描述符继续接收新的数据 */
         rel: Rx_Desc[i].Stat = DMA_RX_OWN;

         if (++i == NUM_RX_BUF) i = 0;
     }
     while (!(Rx_Desc[i].Stat & DMA_RX_OWN));
    
     RxBufIndex = i;

     /*
        DMASR DMA的状态寄存器(DMA status register)
        位7 RBUS:接收缓冲区不可用状态 (Receive buffer unavailable status)
                 此位指示接收列表中的下一个描述符由CPU所拥有,DMA无法获取。接收过程进入挂起状态。
                  要恢复处理接收描述符,CPU应更改描述符的拥有关系,然后发出接收轮询请求命令。如果
                  未发出接收轮询请求命令,则当接收到下一个识别的传入帧时,接收过程会恢复。仅当上一
                  接收描述符由DMA所拥有时,才能将ETH_DMASR[7]置1。
    
        DMAIER的接收缓冲区不可用中断RBUIE是bit7,对于的接收缓冲区不可用状态在DMA状态寄存器中也是bit7。
     */
     if (ETH->DMASR & INT_RBUIE)
     {
         /* 接收缓冲区不可用,重新恢复DMA传输 */
         ETH->DMASR = ETH_DMASR_RBUS;
         ETH->DMARPDR = 0;
     }
    
     /*
        DMASR DMA的状态寄存器(DMA status register)
        这里实现清除中断挂起标志
        位16 ETH_DMASR_NIS:所有正常中断 (Normal interrupt summary)
        位15 ETH_DMASR_AIS:所有异常中断 (Abnormal interrupt summary)
        位6  ETH_DMASR_RS :接收状态 (Receive status)
                            此位指示帧接收已完成,具体的帧状态信息已经包含在描述符中,接收仍保持运行状态。
     */
     ETH->DMASR = ETH_DMASR_NIS | ETH_DMASR_AIS | ETH_DMASR_RS;

#if uCOS_EN == 1
     OSFlagPost ((OS_FLAG_GRP  *)&FLAG_TCPnet,
                   (OS_FLAGS      )0x0001,
                   (OS_OPT        )OS_OPT_POST_FLAG_SET,
                   (OS_ERR       *)&err);
     OSIntExit();                          
#endif
}
回复 点赞 举报
版主
发表于 2017-11-23 08:25:45    楼主|
21.4.4 修改RL-TCPnet的时间基准更新任务


        修改RL-TCPnet的时间基准更新任务,添加事件标志函数:OSFlagPost。
/*
*********************************************************************************************************
*    函 数 名: AppTaskStart
*    功能说明: 这是一个启动任务,在多任务系统启动后,必须初始化滴答计数器。本任务主要实现RL-TCPnet的时间
*             基准更新。
*    形    参: p_arg 是在创建该任务时传递的形参
*    返 回 值: 无
     优 先 级: 2
*********************************************************************************************************
*/
static  void  AppTaskStart (void *p_arg)
{
     OS_ERR      err;

   (void)p_arg;
    
     CPU_Init();    /* 此函数要优先调用,因为外设驱动中使用的us和ms延迟是基于此函数的 */
     bsp_Init();  
     init_TcpNet ();/* 初始化RL-TCPnet */
    
     BSP_Tick_Init();
    
#if OS_CFG_STAT_TASK_EN > 0u
     OSStatTaskCPUUsageInit(&err);  
#endif

#ifdef CPU_CFG_INT_DIS_MEAS_EN
    CPU_IntDisMeasMaxCurReset();
#endif
  
     /* 创建任务 */
    AppTaskCreate();

     /* 创建任务间通信机制 */
     AppObjCreate();  
    
    while (1)
     {
         /* RL-TCPnet时间基准更新函数 */
         timer_tick ();
        
         OSFlagPost ((OS_FLAG_GRP  *)&FLAG_TCPnet,
                       (OS_FLAGS      )0x0001,
                       (OS_OPT        )OS_OPT_POST_FLAG_SET,
                       (OS_ERR       *)&err);
        
         OSTimeDly(100, OS_OPT_TIME_PERIODIC, &err);
    }
}
回复 点赞 举报
版主
发表于 2017-11-23 08:26:06    楼主|
21.4.5 修改RL-TCPnet的网络主任务


        修改RL-TCPnet的网络主任务,函数main_TcpNet的调用不再采用轮询方式,改成事件标志等待方式,即修改为如下形式:
/*
*********************************************************************************************************
*    函 数 名: AppTaskTCPnet
*    功能说明: RL-TCPnet网络主任务
*    形    参: p_arg 是在创建该任务时传递的形参
*    返 回 值: 无
     优 先 级: 3
*********************************************************************************************************
*/
static void AppTaskTCPnet(void *p_arg)
{
     OS_ERR  err;
     CPU_TS   ts;
    
     (void)p_arg;
          
     while(1)
     {
         /* RL-TCPnet处理函数 */
         OSFlagPend ((OS_FLAG_GRP  *)&FLAG_TCPnet,
                       (OS_FLAGS      )0x0001,
                       (OS_TICK       )0,
                       (OS_OPT        )OS_OPT_PEND_FLAG_SET_ANY + OS_OPT_PEND_FLAG_CONSUME,
                       (CPU_TS       *)&ts,
                       (OS_ERR       *)&err);
        
         while (main_TcpNet() == __TRUE);
     }  
}
回复 点赞 举报
版主
发表于 2017-11-23 08:26:21    楼主|
21.4.6 最后特别注意优先级安排


        最后,用户要特别注意几个任务的优先级安排,非常重要。
1、RL-TCPnet的时间基准更新任务一定要是最高优先级任务。
2、RL-TCPnet的网络主任务,即调用函数main_TcpNet的任务是次高优先级任务。
3、应用层的任务要比前面两个任务的优先级都低。
回复 点赞 举报
版主
发表于 2017-11-23 08:26:42    楼主|
21.5 FreeRTOS系统实例修改方法


        下面针对FreeRTOS系统要做的具体修改做个说明,我们以例程:V6-1026_RL-TCPnet实验_BSD Socket服务器之TCP(FreeRTOS)为例。通过修改函数send_frame,以太网中断和时间基准更新任务都给网络主任务发事件标志,让其得到实时执行,从而实现高效的事件触发框架。
回复 点赞 举报
12下一页
高级模式
您需要登录后才可以回帖 登录 | 注册
关闭

站长推荐 上一条 /7 下一条

快速回复 返回顶部 返回列表
  1. time最新主题
  2. recommend推荐主题
  3. hot热门主题
  4. post 我的帖子
-

推荐专区

技术干货集中营

专家问答

用户帮助┃咨询与建议┃版主议事

工程师杂谈

工程师创意

工程师职场

论坛电子赛事

社区活动专版

发烧友活动

-

嵌入式论坛

ARM技术论坛

Android论坛

Linux论坛

单片机/MCU论坛

FPGA|CPLD|ASIC论坛

DSP论坛

嵌入式系统论坛

-

电源技术论坛

电源技术论坛

无线充电技术

-

硬件设计论坛

PCB设计论坛

电路设计论坛

电子元器件论坛

控制|传感

总线技术|接口技术

-

测试测量论坛

LabVIEW论坛

Matlab论坛

测试测量技术专区

仪器仪表技术专区

-

EDA设计论坛

multisim论坛

PADS技术论坛

Protel|AD|DXP论坛

Allegro论坛

proteus论坛|仿真论坛

EasyEDA-中国人自已的EDA工具

Orcad论坛

-

综合技术与应用

电机控制

智能电网

光电及显示

参考设计中心

汽车电子技术论坛

医疗电子论坛

-

开源硬件

-

无线通信论坛

无线通信技术专区

天线|RF射频|微波|雷达技术

-

IC设计论坛

芯片测试与失效分析

Mixed Signal/SOC[数模混合芯片设计]

Analog/RF IC设计

设计与制造封装测试

-

厂商专区

TI论坛

TI Deyisupport社区

-

检测技术与质量

电磁兼容(EMC)设计与整改

安规知识论坛

检测与认证

-

消费电子论坛

手机技术论坛

平板电脑/mid论坛

音视/视频/机顶盒论坛

-

电子论坛综合区

聚丰众筹官方社区

新人报道区

聚丰供应链

-

论坛服务区

-

供求信息发布

供需广告

招聘┃求职发布区

电子展览展会专区

88lifa利发国际娱乐

百度360搜索搜狗搜索