ZYNQ:freeRTOS与lwip的基本运行逻辑

1 篇文章 0 订阅

前言

  1. 核验基本流程,了解freeRTOS控制多通道外设的基本方法和策略。

例程实现

xilinx有freertos的例程,可以先了解例程的功能。下载程序,看看程序运行结果,在此基础上,测试自己编写的代码。

直接run as例程,但是端口没有任何输出,意识到没有初始化任何端口。于是,按照初始化流程,添加UART程序等。

添加串口,程度SDK Terminal没有任何反应。于是,重新下载前期的LED闪烁程序,选择野火调试助手,能够正常接收字符。这意味着,xilinx的串口工具存在一些问题,选择野火调试工具更加可靠。

例程功能是,设计两个任务,分别是每秒向一个队列中发送相同字符的TxTask,以及打印队列字符的RxTask。给整个任务设定了一个10s计时器,计时到会触发vTimerCallback函数。在此函数中,满足一定条件会打印信息以及删除两个任务。

避免深究freertos背景以及stm32移植内容。当看到文档中包含amazon标记时,好奇此公司与freertos的关系。

添加新逻辑

例程的逻辑清晰,可以按照基本逻辑添加GPIO与Uart等。

注重基本功能的实现,即在目标功能实现基础上理解函数逻辑和流程等。比如在考虑如何设计一个测试功能时,看到xQueueCreate函数,奇怪如何创建一个内存区域以及如何调用。但是,在理解函数时,却完全无法理解并陷入其中。

考虑在gpioTask中添加sleep延时逻辑,但是考虑到整个程序的执行逻辑不明,因此似乎有必要了解RTOS的延时机制。此帖提醒,延时机制与任务挂起之间的关系。

添加的任务逻辑如下。野火调试助手显示,确实其它两个任务关闭后,此任务仍然进行中。

static void gpioTask( void *pvParameters )
{
    const TickType_t x1second = pdMS_TO_TICKS( DELAY_1_SECOND );
    /* Delay for 1 second. */

    for(;;)
    {
        print("gpio task\r\n");
        vTaskDelay( x1second );
    }


}

问题是,在实现了基本逻辑功能后,就没有任何念头:关于实现任何具体的目标功能。这需要重新回顾,前期选择freeRTOS系统的主要目的:比如多个CAN外设同时接收和发送CAN帧。

目标、预期和功能,这些才是首要的。理解各种模型框架,需要建立在功能设计和解决问题基础上。否则,就会完全陷入到各种概念或者对象中。

can口逻辑

实现功能,同时让八个CAN口发送CAN帧。

这个功能有什么意义了?如果只是单纯实现特定功能,确实只会让自己失去方向,纠结于各种技术细节。

设计的基本逻辑是,xilinx已经搭建好freertos系统,只要按照函数设计每个task即可。但是,按照多线程逻辑重新实现简单功能,又没有特别重要的意义。此时,或许可以考虑再次实现rolf_ernst论文基本策略。

基本预期是,能够实现QT、嵌入式、裸机、PCB等所有方面功能,但是是否能够实现既定的意义,不清楚。

以太网功能实现

实现基本的以太网帧收发,实现以太网帧转发CAN帧功能,在此基本上测试转换的时间是多少。

想要实现qt的帧收发,但是目前没有太大意义。

这个到是可以理解,逐步提升CAN带宽,并测量延时。

每条通路的带宽,周期数据特性不同,采用什么缓存方案?有种偏向,觉得实验是可以做得,有种跃跃欲试。

基本参考,数据发送lwip

参考例程,小梅哥lwip资料,实现最简单的收发。感知什么基本内容?忽略协议理论等内容。

先找好参考资料,比如按照米联客例程,实现特定功能的以太网收发,熟悉基本流程。

实现基本的lwip echo。感觉不错,但是感觉过于强烈,没有感知过程。

忽略lwip-uart的协议转换逻辑,聚焦uart是如何从lwip拿到以太网帧数据的。基于这个基本逻辑,思考如何实现以太网和CAN帧之间的转化。

尝试理解lwip-uart的所有逻辑和实现,是没有意义的。

如何拿到以太网帧数据?echo.c文件中包含recv_callback函数,参数中pbuf P中,p->paylaod就是获得的以太网帧数据。

err_r recv_callback(void *arg, struct tcp_pcb *tpcb,
                               struct pbuf *p, err_t err)
{
    /* do not read the packet if we are not in ESTABLISHED state */
    if (!p) {
        tcp_close(tpcb);
        tcp_recv(tpcb, NULL);
        print("error recv_callback\r\n");
        return ERR_OK;
    }
//
//  /* indicate that the packet has been received */
//  tcp_recved(tpcb, p->len);//这里接收内容
//
//  /* echo back the payload */
//  /* in this case, we assume that the payload is < TCP_SND_BUF */
//  if (tcp_sndbuf(tpcb) > p->len) {
//      err = tcp_write(tpcb, p->payload, p->len, 1);
//  } else
//      xil_printf("no space in tcp_sndbuf\n\r");

    //获取pbuf内容,并直接打印
    char *original_payload = (char *)p->payload;
    xil_printf("uart 通信测试:%s\r\n",original_payload);

    /* free the received pbuf */
    pbuf_free(p);

    return ERR_OK;
}

在这个函数理解基础上,回顾echo例程的整体逻辑,尝试实现以太网和CAN之间的协议转换。右键函数open call hierarchy,可以获得此函数的调用关系。

A[main]-->B[start_application]
B[start_application]-->C[tcp_accept(pcb,accept_callbalk)]
C[tcp_accept(pcb,accept_callbalk)]-->D[accept_callbalk]
D[accept_callbalk]-->E[tcp_recv(newpcb,recv_callback)]

echo文件中,主要实现两个回调函数,分别指向结构体tcp_pcb与结构体tcp_pcb_listen中的回调函数recv_callbackaccept_callback
这意味着,lwip中回调函数是功能实现的一个重要逻辑。

存在两个问题

  1. 为什么这个函数调用关系不在中断或者while逻辑中,仍然可以一直工作
  2. 哪些关键逻辑才是重要,从而自己写程序时,能够精简内容。

由于不理解函数调用机制,以及函数流最终停留在哪里,有必要通过debug理解其中的逻辑。但是,debug as出现无法工作。尝试使用printf打印定位函数流。

通过增加断点,发现奇怪的地方。首先,程序是一直处于main循环中。但是程序问题总是可以在助手发送以太网帧时,可以激活recv_callback函数。问题是,start__application触发的这个函数,其它地方没有才是。结果是,while函数激活xemacif_input(echo_netif),但是函数里面的if和ifdef会编译错误。实际函数进入了阴影部分。

不忽略每个流程细节。后来发现,通过函数中小逻辑,将用户定义的结构体与lwip定义的全局结构体绑定。不过,还不知道,lwip是如何周期性得获取MAC FIFO或者DMA中的数据。

目前面临的问题:

  1. 函数流到底在哪里?
  2. 结构体中的pbuf与netif的结构是如何建立联系的?之所有强调全局结构体,是因为自己编写函数时,一般是围绕此结构体展开。

pcb.c文件中包含全局结构体,问题是什么时候将两者绑定,以及什么时候触发这个逻辑的?

主体逻辑是,通过main函数中的结构体与库文件中的结构体建立联系。关键是接口如何与pcb的结构体建立联系的?结果是,tcp_fast或者tcp_slow函数不影响数据接收。

考虑使用屏蔽特定语句的方式,判断那些函数影响以太网帧接收。

仍然分不清,到底这个数据从哪里来的,为什么直接就可以获取相关的数据?

明确两个问题:

  1. 以太网数据是如何通过**low_level_input(struct netif netif)**拿到?
    明明没有参与寄存器相关的操作

  2. 获取的数据又是怎样通过callback函数进入上层?最后触发start_application中配置的函数?

  3. 回调函数重要,明确三个回调函数,可以说明主要函数触发逻辑

重新梳理说明,了解当前程序分析的目的,避免解释概念。

直接应用lwip,注重初始化以及callback函数的应用,方便搭建基本功能逻辑。

分以下几个步骤:

  1. 注释核心逻辑;考虑直接在原工程上添加CAN逻辑。
  2. 建立新工程,实现串口接收
  3. 在串口工程中添加以下以太网逻辑。

结果是,某个不起眼的define 定义函数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值