FreeRTOS和LwIP联合移植

所需积分/C币:31 2017-09-01 09:38:10 25.95MB PDF

FreeRTOS和LwIP联合移植,针对移植部分书籍截取篇
第12章基于 FreeRTOS的LwP协议栈移植295 口以太网接口任务( Ethernet Interface Task)用于接收来自物理网卡的数据报文,同时将收 到的报文通过 FreeRTOS提供的邮箱传递给TCPP协议栈任务。以太网接口任务平时处 于挂起状态。当STM3F107收到报文时,将产生接收报文中断 Ethernet isr”,该中断 以信号量的方式将以太网接口任务激活。 口应用程序使用TCP/P协议栈提供的 Sequential API接口访问LwP,同时这两个独立 的任务需要使用 FreeRTOS提供的邮箱机制实现彼此之间信息的交互。值得注意的是, Sequential aPl接口函数在 FrccRTOS操作系统运行环境下是“阻塞”函数,也就是说应用 程序任务在调用 Sequential API接口函数时,将会被阻塞,直到收到来自TCP/P协议栈返 回的消息应答。 口基于LwP的TCP/P协议栈与应用程序运行在两个独立的任务中。 接下来将根据图12.1提供的程序框架,详细介绍如何将LwP移植到Fτ eRTOS操作系统上, 122 FreeRTOS下以太网驱动程序的移植 以太网驱动程序中关于物理网卡初始化、DMA操作、报文接收和发送等函数在本书的第11 章中已经做∫详细阐述,这部分驱动程序并不需要做改变,需要改变的是以太网报文接收中断函 数。其代码实现如下所示: void ETH IRQHandler(void) portBASE TYPE xigherPriorityTaskwoken pdFALSE; 检查是否收到报文 while (ETH GetRxPktsize(!=0) 通知以太网接口任务接收报文 xSemaphoreGiveFromISR( s sEmaphore, xHigherPriorityTaskWoken )i 清除DMA的RX中断 ETH DMAClearITPendingBit (ETH DMA IT R)i ETH DMAClearITPendingBit(ETH DMA IT NIS)i 〃/进行上下文切换,确保最高优先毁的阻塞任务可以执行 if( xHigherPriorityTaskWoken ! pdFALSE portEND SWITCHING ISR( xHigherPriorityTaskWoken )i 该中断函数调用了 FreeRTos提供的中断信号量释放函数 x Semaphore Give FromISR,因信 号量 s SEmaphore阻塞的仼务将被激活,并得到执行。对于本移植程序而言,以太网接口任务 ethernetif input将得到执行,它将调用报文接收函数接收报文。 296第四篇移植篇 12.3Lw|P程序移植 该部分的移植包含两个部分:以太网接口 ethernetif.c的移植和操作系统模拟层 sys arch.c的 移植。 与本书第11章介绍的不同,本章介绍的 ethernetif.c文件将建立一个以太网接口任务,用于接 收以太网数据报文。接下来将详细介绍 ethernet:c文件中各函数的移植过程。 1231以太网接口文件 ethernet. c的移植 1. low level init:数 该函数的源代码如下 static void low level init(struct netif *netif) *设定MAC地扯长度,默认是6字节* netif->hwaddr len= ETHARP HWADDR LEN 设定网十MAC地址 netif->hwaddr[0]-MACaddr[OJi netif->hwaddr [1]- MACaddr[1]: netif-hwaddr [2]= MA Caddr[2 Lf->hwaddr [31= MACaddr[3 netif->hwaddr[ 41= MACaddr:4.; netif-hwaddr [5 ddr: i /*设定网卡每一包最大的发送数据字节数/ netif->mtu 1500 指定十共备广播、AR功能s1 NETIF- FLAG ETHARP1 netit>flags NETIF FLAG BROAl NETIF FLAG LINK UP s PxNetIf netif; k。初始化DM发送描述符链表*/ ETH_ DMATxLescChainInit (DMATxDscrTab, &Tx Buff[01[O] ETH TXBUENB *初始化DMA接收描述符链表 ETH DMARxDescChainInit (DMARxDscrTab, &Rx Buft[][O]r ETH RXBUFNB) /*创建二进制信号量 s: SEmaphore,该信号量用于接收报文* 【 sEmaphore=NULL) seMaphore xSemaphoreCreateCounting (20, 0)i /*创建二进制信号量 xTxSemaphore,该信号量用于发遂报文* if (xfxSemaphore = NULL) vSemaphoreCreateBinary (xTxSemaphore); } /*使能接收中断 第12章基于 FreeRTOS的LwP协议栈移植297 int立; for(=0;立< ETH RXBUENB;主++) ETH DMARxDescReceiveIrConfig(&DMARxDscrTablil ENABLE); #ifdef CHECKSUM BY HARDWARE *发送数据帧时,硬件生成CRC校验字节* int i: for(i=0: i<ETH TXEUFNB:i++) ETH DMATxDescchecksumInsertionConfig(&DMATxDscrTab [i], ETH DMATxDesc ChecksumTCPUDPICMPFull) } tends /*创建以太网接口任务* xTaskCreate(ethernetif input, (signed char*)"EthIf Tsk" netifINTEREACE TASK STACK SIZE, NULL,050 4 netifINTERFACE TASK PRIORITY NULL); 启动STM32F107的以太网控制器相关功能*/ ETH start); 由以上代码可以看到,该函数的内容与第11章介绍的函数1 ow level init内容大致相同,所 不同的是本函数中用粗体标识的部分:创建一个二进制信号量用于接收报文、创建一个二进制信 号用于发送报文、创建一个以太网接∏任务。 在调用 XTaskCreate创建任务时,宏 netifINTERFACE TASK STACK size定义了该任务堆 栈的大小,本文中将其定义为400。宏 netifINTERFACE TASK priority则定义了该任务的优 先级,定义如下 #define netifINTERFACE TASK PRIORITY e (configMAX PRIORITIES -1) 2. ethernetif input函数 该函数就是本章所介绍的以太网接口任务,它用于从底层物理树卡读取报文,并将该报文向 上传递给LwP协议栈函数 ethernet input进行处理。其源代码如下: vcid ethernetif input void paRameters struct pbuf *pi iE (xSemaphoreTake( s_ sEmaphore, emacBLOCK TIME WAITING FOR INPUT)--paTRUE 298第四篇移植篇 p =low level input( s pxNetIf )i if (ERR_OK !-3PxNetIf->input:( p, s pxNetrr)) pbuf free(p); P=NULLF 由以上代码可以看到,任务 ethernetif input平时处于阻塞状态,当信号量 S SEmaphore被以 太网接收报文中断释放时,该任务得以执行。 3. low_level input函数 该的数无需做改动,读者可以参考本书第11章中关于该函数的移植代码。 4. low level output函数 该函数的源代码如下所示。在本函数中,使用了二进制信号量 X TxScmaphore,这是因为该函 数可能被多个任务调用,因此需要使用 XTxSemaphore来保护DMA发送缓冲区的临界区资源 static err_t low level_ output(struct netif *netif, struct pbuf p struct pbuf uint32t u8 *buffer if (xSemaphoreTake (xTxSemaphore, 250) buffer =(u8 *)ETH CetCurrentTxBuffer(); cor (q= p q!= NULLi q =q->next *将pbuf中的数据拷贝至发送缓存 memcpy(u8 t*)&bufferllr q->payload, ->len): 9-l ETHExPkt ChainMode(主) x SemaphoreGive (xTx Semaphore) eturn ERR_○K冫 12.32操作系统模拟层文件 sys arch.c的移植 接下来是操作系统模拟层 sys arch,c的移植。如前文所述,在LwlP中,操作系统模拟层是 LwIP协议栈的一部分,它存在的目的是方便将LwP移植到各种不同的操作系统上,它为操作系 统和LwP协议栈之间提供了一个接口桥梁,当用户移植LwP到一个新的操作系统的时候,只需 要修改操作系统模拟层内的各函数即可。对于如何实现操作系统模拟层, sys achⅸxt文件给出了 第12章基于 FreeRTOS的LwP协议栈移植299 详细说明。总的说来,操作系统模拟层主要完成了与信号量、消息邮箱机制、线程相关的功能 接下来将对 sys arch.c、 sys arch. h文件的代码实现进行更深层次的解释。 首先来看如下代码: typedef xSemaphoreHandle sys sem ti typedef xQueueHandle s typedef xTaskHandle sys thread t 在LwP中,信号量使用变量 sys sem t定义,队列消息使用变量 sys mbox t定义,线程则 使用变量 sys thread t定义。因此为了将Lw移植到 FreeRTOS操作系统,在 sys arch.h文件中, 需要使用 typedef的方式对上述3个变量进行重定义。 其次, sys arch.c是信号量、消息队列机制、线程相关的功能的实现代码,本章接下来的内容 将着重讨论 sys arch.c內的各函数实现 1. sys mbox new函数 该函数的功能是使用 Freertos提供的消息队列机制创建一个空的消息队列。在 FreeRToS 中,消息队列创建函数是 xQueue Create。创建的邮箱大小由 sys arch.h中的宏定义 archES〔 QUEUE LENGTH实现,在本书中,将其定义为8。 sys mbox ncw的具体代码如下: sys nbox t sys mbox new(int size) x QueueHande mbox; (void) size: *创建队列*/ nbox- xQueueCreate( archMESG_ QUEUE_ LENGTH, si eof( void *) #if SYS STATS ++iwip stats. sys. mbox. used; Iwip stats. sys, mbox, max lwip stats. sys: .moox, used #endif return mbox 2. sys mbox free I数 该函数的功能与 sys mbox new相反,它用于删除一个队列。当该队列中还有未被取出的消 息时,该函数应当报错,并通知应用程序。其代码如下: voidsysmbxfree(sysmboxtmbox if( uxQueueMessageswaiting( mbox ) *报错 portNOY 普主 t SYS STAs 300第四篇移植篇 1 Stats, sy,mbx,er工 fendt 删除该队列 vQueueDelete( mbox ); t SYs S里2TS -lwip stats. sys. mbox used; #endif sys mbox post函数 该函数用丁将消息发送至消息队列中。该函数是一个阻塞函数。当消息被发送至队列后,该 函数才退出阻塞状态。其代码如下: void sys mhox post(sys mbox t mbox, void *data) while xQueueSendToBack (mbox, adata, portMAX DELAY)! PdTRUE 4.Sys_ mbox trypost函数 该图数用于尝试将某个消息发送至消息队列中,当消息被成功投递后,则返回成功,否则返 回失败。 err t sysmbox_ trypost(sys mbox t mbox, void *msg) err t resulti i f( xQueue Send( mbox &msg, 0 )= pdPASS result ERR OK: e⊥se //不能成功投递,可能是队列满了 result= ERR M #if SYS STATS Iwip stats. sys. mbox.err++; #endif* SYS STATS */3 eturn result 5. sys arch mbox fetch函数 该函数用于从消息队列中取出一条消息。该函数是一个阻塞函数。调用该函数的线程若未取 到消息,则在形参 timeout所指定的时间内,该线程被阻塞。当超过 timeout所指定的时间后,该 线程恢复至就绪状态。若 timeout为0,则调用该函数的线程一直被阻塞,直到收到消息。 4 u3z t sys arch boz fetch(sys mbox_t mbox, void msg, u32-tWS timeout) 第12章基于 FreeRTOS的LwP协议栈移植301 a void *dummyptr: portfickTypc StartTimer EndTime, Elapsed; i StartTime xTaskGetTickCount(); if ( msg --NULL msg =&dummyptri if timeout 1=0) 在 t timeout时间内楼收消息 if( PdT QueueReceive( mbox,&(*msg), timeout ort'TICK RATE NS) EndTime=xTaskGetTickCount(): Elapsed =(EndTime startTime)* portTICK RATE MS; return【 Elapsed) e1se//超时退出 *msg NULLi return SYS ARCH TIMEOUT: el se 太直到收到消息才逄出阻塞状态* while( pdTRUE- xQueueReceive( mbox, &(msg), portMAX DELAY ) EndT⊥me= tAs kget⊥ ckCsunt() Elapsed =(EndTime Starttime) portTICK RATE MS: return( Elapsed )i// return time blocked TODo test 6. sys arch mbox tryfetch函数 该函数尝试从消息队列中取出消息。它是一个非阻塞函数。当取到消息时,则返回成功,否 则立即退出,返回“队列空” u32 t sys arch mbox tryfetch(sys nbox t abox, void **msg) void *dummyptr; if( msg NULL msg &dummyptri if( pdTRUE== xQueueReceive( mbox, &(*msg), 0)) return ERR OK i 302第四篇移植篇 else return sYS MBOX EMPTY; 7. sys sem new函数 该困数用于创建一个信号量,共中形参comt指明了当前信号量的状态。若 count为0,则该 信号量在创建时就被“取走”(take)了。其代码如下 sYs sem t sys sem new (u8 t count) xSemaphoreHandle sEmaphore; 创建二进制信号量 vSemaphoreCreateBinary( xSemapore)i if( sEmaphore = NULL) fif SYS SATS - p stats. sys.sem erri return SYS SEM NUlL; f(count ==0) xSemaphoreTake (sEmaphore, 1); tif SYS STATS ++lwip stats. sys.sem, used if (lwip stats. sys. sem, max I stats, sys. sem, used) e Iwip stats, sys. sem. max- lwip atats sys. sen used fendi return sEmaphore; 8. sys arch sem wait I函数 该函数是一个阻塞函数。调用该函数的线程在形参 timeout指定的时间内被阻塞。若 timeout 为0,则调用该函数的线程将一直被阻塞,直到等待的信号量被释放。当该函数取到信号量时, 它将返回取得该信号量所占用的时间。其代码如下: u32 t sys arch sem wait(sys sem t sem, u32_t timeout) portTickType StartTime, EndTime, Ela startTime xTaskGetTickCount \,apsed if (timeout != 0) if( xSemaphore'ake( sem, timeout/ portCICK RATE MS )=m pdTRUE

...展开详情

评论 下载该资源后可以进行评论 1

自由自在的斑 资料很好,对学习很有用
2017-10-24
回复
img
因为卡农

关注 私信 TA的资源

上传资源赚积分,得勋章
    最新推荐