|

楼主 |
发表于 2017-11-13 16:02:04
|
显示全部楼层
21.4 uCOS-III系统实例修改方法
下面针对uCOS-III系统要做的具体修改做个说明,我们以例程:V6-1025_RL-TCPnet实验_BSD Socket服务器之TCP(uCOS-III)为例。通过修改函数send_frame,以太网中断和时间基准更新任务都给网络主任务发事件标志,让其得到实时执行,从而实现高效的事件触发框架。
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);
- }
复制代码
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
- }
复制代码
21.4.3 修改以太网中断函数
修改ETH_STM32F4xx.c文件中的以太网中断函数,此函数的末尾添加事件标志函数:OSFlagPost(宏定义uCOS_EN在bsp.h文件里面使能,针对教程配套例子做的定义,方便管理。大家自己搞时,不必受此限制)。
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);
- }
- }
复制代码
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);
- }
- }
复制代码
21.4.6 最后特别注意优先级安排
最后,用户要特别注意几个任务的优先级安排,非常重要。
1、RL-TCPnet的时间基准更新任务一定要是最高优先级任务。
2、RL-TCPnet的网络主任务,即调用函数main_TcpNet的任务是次高优先级任务。
3、应用层的任务要比前面两个任务的优先级都低。 |
|