打印
[STM32F4]

STM32F407 移植ucosIII+LWIP2.03 ping不通

[复制链接]
2302|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
liuxiang5119|  楼主 | 2019-2-27 12:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
STM32F407 移植ucosIII+LWIP2.03  ping不通
现在不知道该怎么找问题,各位大神给点意见
主要几个文件如下:
一、以太网驱动程序移植
1、stm32cube导出的源码对以太网物理层上的初始化主要更改下ETH中断部分处理函数
   中断实现更改为ucos自带的中断函数
   BSP_IntPrioSet (BSP_INT_ID_ETH, 5);//APP_CFG_INTERRUPT_ETH_PRIO
        /* configurate ISR of ETH*/
        BSP_IntVectSet(BSP_INT_ID_ETH, LwipBSP_STM32_ETH_IntHandler);
        /* enable NVIC interupt  of ETH*/
        //void HAL_NVIC_EnableIRQ(IRQn_Type IRQn);
        BSP_IntEn(BSP_INT_ID_ETH);
        中断接口函数
        void LwipBSP_STM32_ETH_IntHandler(void)
{

        HAL_ETH_IRQHandler(&heth);

}
中断回调函数,实现信号量的发布,然后数据接收函数做数据处理
void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
{
        //ethernetif_input(&lwip_netif);      //从网络缓冲区中读取接收到的数据包并将其发送给LWIP处理
        OS_ERR err;
        OSSemPost(&s_xSemaphore,OS_OPT_POST_1,&err);//发送信号量
        LWIP_ASSERT("OSSemPost ",err == OS_ERR_NONE );
}
2、信号量s_xSemaphore的创建在 low_level_init   主要增加了接收信号量s_xSemaphore 创建以及以太网接口任务的创建
   书中还创建了一个发送信号量,这里发送如果用阻塞模式,则不创建该信号量
#if WITH_RTOS // WITH_RTOS //*********lx修改*********
        /* create a binary semaphore used for informing ethernetif of frame reception */
        //os_err = sys_sem_new(&s_xSemaphore, 1);
    OSSemCreate(&s_xSemaphore,
                "s_xSemaphore",
                0u,
                &os_err);
        /* create the task that handles the ETH_MAC */
        OSTaskCreate((OS_TCB         * )&ethernetifTaskTCB,                //任务控制块
                     (CPU_CHAR        * )"ethernetif_input task",                         //任务名字
                     (OS_TASK_PTR )ethernetif_input,                         //任务函数
                     (void                * )netif,                                                //传递给任务函数的参数
                     (OS_PRIO          )ethernetif_CFG_TASK_PRIO,         //任务优先级
                     (CPU_STK   * )&ethernetif_TASK_STK[0],        //任务堆栈基地址
                     (CPU_STK_SIZE)ethernetif_CFG_STK_SIZE/10,        //任务堆栈深度限位
                     (CPU_STK_SIZE)ethernetif_CFG_STK_SIZE,                //任务堆栈大小
                     (OS_MSG_QTY  )0,                                                //任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                     (OS_TICK          )0,                                                //当使能时间片轮转时的时间片长度,为0时为默认长度,
                     (void           * )0,                                                //用户补充的存储区
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                     (OS_ERR         * )&os_err);                                        //存放该函数错误时的返回值
#endif
3、ethernetif_input  函数   该函数实现了从底层物理网卡读取报文,并将报文传递给LWIP协议栈函数 ethernet_input进行处理
   更改为如下所示,处理函数low_level_input为阻塞模式,等待获取信号量s_xSemaphore  
#if WITH_RTOS // WITH_RTOS
        for ( ;; )
        {
                OSSemPend(&s_xSemaphore,
                          0,
                          OS_OPT_PEND_BLOCKING,
                          0,
                          &err);
                //OSSemPend(&s_xSemaphore,0xffffffff,OS_OPT_PEND_BLOCKING,0,&err); //请求信号量
                if (err == OS_ERR_NONE)
                {
                        do
                        {
                                p = low_level_input( netif );
                                if   (p != NULL)
                                {
                                        if (netif->input( p, netif) != ERR_OK )
                                        {
                                                pbuf_free(p);
                                        }
                                }
                        } while (p!=NULL);
                }
        }
#else
4、low_level_input不用做改动   
5、low_level_output  如果是阻塞模式去发送  这里不做修改  
6、源码lwip.c中定义了以太网连接状态的结构体全局变量  这里将osSemaphoreId修改为sys_sem_t
/* Semaphore to signal Ethernet Link state update */
sys_sem_t Netif_LinkSemaphore = NULL;//osSemaphoreId  // lx修改   连接状态查询信号量  屏蔽不用
/* Ethernet link thread Argument */
struct link_str link_arg;
7、连接状态实现函数在ethernetif.c中实现,具体怎么调用,链接状态怎么更新,得具体看下源码实现
二、系统层文件 sys_arch.c文件的修改移植
1、lwipopts.h 系统配置文件,这里暂时使用cube导出的配置  增加 #define NO_SYS  0,
   具体某项是什么功能,感兴趣的可以看源码注释,还是很清晰明了的
2、sys_arch.h文件修改  增加头文件,另外根据ucos更改四个定义  原子pdf文档中说sys_mbox_t不能使用ucos的消息邮箱 这里没理解 是因为ucosII的问题么  这里先用ucos邮箱测试 后期有问题再改
#include "arch/cc.h"
#include "includes.h"

#define LWIP_COMPAT_MUTEX     1
#define LWIP_COMPAT_MUTEX_ALLOWED 1
#define MAX_QUEUES                        OS_CFG_MSG_POOL_SIZE        // 消息邮箱的数量
#define MAX_QUEUE_ENTRIES                 20                                                // 每个消息邮箱的大小

typedef OS_SEM sys_sem_t;          //LWIP使用的信号量
typedef OS_MUTEX sys_mutex_t;      //LWIP使用的互斥信号量
typedef OS_Q  sys_mbox_t;          //LWIP使用的消息邮箱,其实就是ucos中的消息队列
typedef CPU_INT08U    sys_thread_t;//线程ID 也就是任务优先级
3、cc.h 增加临界保护代码
#include "includes.h"//记得头文件必须添加

typedef int sys_prot_t;

#if CPU_CFG_CRITICAL_METHOD == 1
#define SYS_ARCH_DECL_PROTECT(lev)
#define SYS_ARCH_PROTECT(lev)                CPU_INT_DIS()
#define SYS_ARCH_UNPROTECT(lev)                CPU_INT_EN()
#endif
#if CPU_CFG_CRITICAL_METHOD == 3  
#define SYS_ARCH_DECL_PROTECT(lev)        u32_t lev
#define SYS_ARCH_PROTECT(lev)                lev = CPU_SR_Save()         //UCOS III中进入临界区,关中断
#define SYS_ARCH_UNPROTECT(lev)                CPU_SR_Restore(lev)                //UCOS III中退出A临界区,开中断
#endif
#define LWIP_PROVIDE_ERRNO
3、sys_arch.c 文件的实现如下  
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/mem.h"
#include "lwip/stats.h"

#if !NO_SYS
//#include "cmsis_os.h"
#include "os_cfg_app.h"
#include "includes.h"

#if defined(LWIP_SOCKET_SET_ERRNO) && defined(LWIP_PROVIDE_ERRNO)
int errno;
#endif
//当消息指针为空时,指向一个常量pvNullPointer所指向的值.
//在UCOS中如果OSQPost()中的msg==NULL会返回一条OS_ERR_POST_NULL
//错误,而在lwip中会调用sys_mbox_post(mbox,NULL)发送一条空消息,我们
//在本函数中把NULL变成一个常量指针0Xffffffff
const void * const pvNullPointer = (mem_ptr_t*)0xffffffff;
/*-----------------------------------------------------------------------------------*/
//  Creates an empty mailbox.
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
{
       
        OS_ERR err;
        if(size>MAX_QUEUE_ENTRIES)size=MAX_QUEUE_ENTRIES;                //消息队列最多容纳MAX_QUEUE_ENTRIES消息数目
        OSQCreate((OS_Q*                )mbox,                                //消息队列
              (CPU_CHAR*        )"LWIP Quiue",                //消息队列名称
              (OS_MSG_QTY        )size,                                //消息队列长度
              (OS_ERR*                )&err);                                //错误码
        if(err==OS_ERR_NONE) return ERR_OK;
        return ERR_MEM;
}

/*-----------------------------------------------------------------------------------*/
/*
  Deallocates a mailbox. If there are messages still present in the
  mailbox when the mailbox is deallocated, it is an indication of a
  programming error in lwIP and the developer should be notified.
*/
void sys_mbox_free(sys_mbox_t *mbox)
{
        OS_ERR err;
       
#if OS_CFG_Q_FLUSH_EN > 0u  
        OSQFlush(mbox,&err);
#endif
       
        OSQDel((OS_Q*        )mbox,
           (OS_OPT        )OS_OPT_DEL_ALWAYS,
           (OS_ERR*        )&err);
        LWIP_ASSERT( "OSQDel ",err == OS_ERR_NONE );
}

/*-----------------------------------------------------------------------------------*/
//   Posts the "msg" to the mailbox.
void sys_mbox_post(sys_mbox_t *mbox, void *msg)
{   
        OS_ERR err;
        CPU_INT08U i=0;
        if(msg==NULL)msg=(void*)&pvNullPointer;        //当msg为空时 msg等于pvNullPointer指向的值
        //发送消息
    while(i<10)        //试10次 //这里原子文档写是必须发送成功  是while死循环 备注下
        {
                OSQPost((OS_Q*                )mbox,               
                            (void*                )msg,
                            (OS_MSG_SIZE)strlen(msg),
                            (OS_OPT                )OS_OPT_POST_FIFO,
                            (OS_ERR*        )&err);
                if(err==OS_ERR_NONE) break;
                i++;
                OSTimeDlyHMSM(0,0,0,5,OS_OPT_TIME_HMSM_STRICT,&err); //延时5ms
        }
        LWIP_ASSERT( "sys_mbox_post error!\n", i !=10 );         
}


/*-----------------------------------------------------------------------------------*/
//   Try to post the "msg" to the mailbox.
//   相对于sys_mbox_post,只发一次 发送失败不会发送第二次
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{
        OS_ERR err;
        if(msg==NULL)msg=(void*)&pvNullPointer;//当msg为空时 msg等于pvNullPointer指向的值
        OSQPost((OS_Q*                )mbox,               
                        (void*                )msg,
                        (OS_MSG_SIZE)sizeof(msg),
                        (OS_OPT                )OS_OPT_POST_FIFO,
                        (OS_ERR*        )&err);
        if(err!=OS_ERR_NONE) return ERR_MEM;
        return ERR_OK;
}

/*-----------------------------------------------------------------------------------*/
/*
  Blocks the thread until a message arrives in the mailbox, but does
  not block the thread longer than "timeout" milliseconds (similar to
  the sys_arch_sem_wait() function). The "msg" argument is a result
  parameter that is set by the function (i.e., by doing "*msg =
  ptr"). The "msg" parameter maybe NULL to indicate that the message
  should be dropped.

  The return values are the same as for the sys_arch_sem_wait() function:
  Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
  timeout.

  Note that a function with a similar name, sys_mbox_fetch(), is
  implemented by lwIP.
*/
u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
{
        OS_ERR err;
        OS_MSG_SIZE size;
        u32_t ucos_timeout,timeout_new;
        void *temp;
        if(timeout!=0)
        {
                ucos_timeout=(timeout*OS_CFG_TICK_RATE_HZ)/1000; //转换为节拍数,因为UCOS延时使用的是节拍数,而LWIP是用ms
                if(ucos_timeout<1)ucos_timeout=1;//至少1个节拍
        }else ucos_timeout = 0;
        timeout = OSTimeGet(&err); //获取系统时间
        //请求消息
        temp=OSQPend((OS_Q*                        )mbox,   
                                (OS_TICK                )ucos_timeout,
                (OS_OPT                        )OS_OPT_PEND_BLOCKING,
                (OS_MSG_SIZE*        )&size,               
                (CPU_TS*                )0,
                (OS_ERR*                )&err);
        if(msg!=NULL)
        {       
                if(temp==(void*)&pvNullPointer)*msg = NULL;           //因为lwip发送空消息的时候我们使用了pvNullPointer指针,所以判断pvNullPointer指向的值
                else *msg=temp;                                                                        //就可知道请求到的消息是否有效
        }   
        if(err==OS_ERR_TIMEOUT)timeout=SYS_ARCH_TIMEOUT;  //请求超时
        else
        {
                LWIP_ASSERT("OSQPend ",err==OS_ERR_NONE);
                timeout_new=OSTimeGet(&err);
                if (timeout_new>=timeout) timeout_new = timeout_new - timeout;//算出请求消息或使用的时间
                else timeout_new = 0xffffffff - timeout + timeout_new;
                timeout=timeout_new*1000/OS_CFG_TICK_RATE_HZ + 1;
        }
        return timeout;
}

/*-----------------------------------------------------------------------------------*/
/*
  Similar to sys_arch_mbox_fetch, but if message is not ready immediately, we'll
  return with SYS_MBOX_EMPTY.  On success, 0 is returned.
*/
u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
{
        return sys_arch_mbox_fetch(mbox,msg,1);//尝试获取一个消息
}
/*----------------------------------------------------------------------------------*/
int sys_mbox_valid(sys_mbox_t *mbox)         
{      
        if(mbox->NamePtr)  
                return (strcmp(mbox->NamePtr,"?Q"))? 1:0;
        else
                return 0;
}                                             
/*-----------------------------------------------------------------------------------*/                                             
void sys_mbox_set_invalid(sys_mbox_t *mbox)   
{                                             
        if(sys_mbox_valid(mbox))
    sys_mbox_free(mbox);
}

/*-----------------------------------------------------------------------------------*/
//  Creates a new semaphore. The "count" argument specifies
//  the initial state of the semaphore.
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
{
        OS_ERR err;
        OSSemCreate ((OS_SEM*        )sem,
                 (CPU_CHAR*        )"LWIP Sem",
                 (OS_SEM_CTR)count,               
                 (OS_ERR*        )&err);
        if(err!=OS_ERR_NONE)return ERR_MEM;
        LWIP_ASSERT("OSSemCreate ",sem != NULL );
        return ERR_OK;
}

/*-----------------------------------------------------------------------------------*/
/*
  Blocks the thread while waiting for the semaphore to be
  signaled. If the "timeout" argument is non-zero, the thread should
  only be blocked for the specified time (measured in
  milliseconds).

  If the timeout argument is non-zero, the return value is the number of
  milliseconds spent waiting for the semaphore to be signaled. If the
  semaphore wasn't signaled within the specified time, the return value is
  SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
  (i.e., it was already signaled), the function may return zero.

  Notice that lwIP implements a function with a similar name,
  sys_sem_wait(), that uses the sys_arch_sem_wait() function.
*/
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
{
        OS_ERR err;
        u32_t ucos_timeout, timeout_new;
        if(        timeout!=0)
        {
                ucos_timeout = (timeout * OS_CFG_TICK_RATE_HZ) / 1000;//转换为节拍数,因为UCOS延时使用的是节拍数,而LWIP是用ms
                if(ucos_timeout < 1)
                ucos_timeout = 1;
        }else ucos_timeout = 0;
        timeout = OSTimeGet(&err);  
        OSSemPend(sem,ucos_timeout,OS_OPT_PEND_BLOCKING,0,&err); //请求信号量
        if(err == OS_ERR_TIMEOUT)timeout=SYS_ARCH_TIMEOUT;//请求超时       
        else
        {     
                timeout_new = OSTimeGet(&err);
                if (timeout_new>=timeout) timeout_new = timeout_new - timeout;
                else timeout_new = 0xffffffff - timeout + timeout_new;
                timeout = (timeout_new*1000/OS_CFG_TICK_RATE_HZ + 1);//算出请求消息或使用的时间(ms)
        }
        return timeout;
}

/*-----------------------------------------------------------------------------------*/
// Signals a semaphore
void sys_sem_signal(sys_sem_t *sem)
{
        OS_ERR err;
        OSSemPost(sem,OS_OPT_POST_1,&err);//发送信号量
        LWIP_ASSERT("OSSemPost ",err == OS_ERR_NONE );
}

/*-----------------------------------------------------------------------------------*/
// Deallocates a semaphore
void sys_sem_free(sys_sem_t *sem)
{
        OS_ERR err;
        OSSemDel(sem,OS_OPT_DEL_ALWAYS,&err);
    LWIP_ASSERT("OSSemDel ",err==OS_ERR_NONE);
        sem = NULL;
}
/*-----------------------------------------------------------------------------------*/
int sys_sem_valid(sys_sem_t *sem)                                               
{
        if(sem->NamePtr)
                return (strcmp(sem->NamePtr,"?SEM"))? 1:0;
        else
                return 0;           
}

/*-----------------------------------------------------------------------------------*/                                                                                                                                                               
void sys_sem_set_invalid(sys_sem_t *sem)                                       
{                                                                              
        if(sys_sem_valid(sem))
     sys_sem_free(sem);
}

/*-----------------------------------------------------------------------------------*/
//osMutexId lwip_sys_mutex;
//osMutexDef(lwip_sys_mutex);
// Initialize sys arch
void sys_init(void)
{
  //lwip_sys_mutex = osMutexCreate(osMutex(lwip_sys_mutex));
}
/*-----------------------------------------------------------------------------------*/
                                      /* Mutexes*/
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
#if LWIP_COMPAT_MUTEX == 0
/* Create a new mutex*/
err_t sys_mutex_new(sys_mutex_t *mutex) {

  osMutexDef(MUTEX);

  *mutex = osMutexCreate(osMutex(MUTEX));


  //*mutex = xSemaphoreCreateMutex();
  if(*mutex == NULL)
  {
#if SYS_STATS
    ++lwip_stats.sys.mutex.err;
#endif /* SYS_STATS */       
    return ERR_MEM;
  }

#if SYS_STATS
  ++lwip_stats.sys.mutex.used;
  if (lwip_stats.sys.mutex.max < lwip_stats.sys.mutex.used) {
    lwip_stats.sys.mutex.max = lwip_stats.sys.mutex.used;
  }
#endif /* SYS_STATS */
  return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
/* Deallocate a mutex*/
void sys_mutex_free(sys_mutex_t *mutex)
{
#if SYS_STATS
      --lwip_stats.sys.mutex.used;
#endif /* SYS_STATS */
                       
  osMutexDelete(*mutex);
}
/*-----------------------------------------------------------------------------------*/
/* Lock a mutex*/
void sys_mutex_lock(sys_mutex_t *mutex)
{
  osMutexWait (*mutex, osWaitForever);
}

/*-----------------------------------------------------------------------------------*/
/* Unlock a mutex*/
void sys_mutex_unlock(sys_mutex_t *mutex)
{
  osMutexRelease(*mutex);
}
#endif /*LWIP_COMPAT_MUTEX*/
/*-----------------------------------------------------------------------------------*/
// TODO
/*-----------------------------------------------------------------------------------*/
/*
  Starts a new thread with priority "prio" that will begin its execution in the
  function "thread()". The "arg" argument will be passed as an argument to the
  thread() function. The id of the new thread is returned. Both the id and
  the priority are system dependent.
*/
extern CPU_STK * TCPIP_THREAD_TASK_STK;//TCP IP内核任务堆栈,在lwip_comm函数定义
//LWIP内核任务的任务控制块
OS_TCB TcpipthreadTaskTCB;

sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread , void *arg, int stacksize, int prio)
{
        OS_ERR err;
        CPU_SR_ALLOC();
        if(strcmp(name,TCPIP_THREAD_NAME)==0)//创建TCP IP内核任务
        {
                OS_CRITICAL_ENTER();        //进入临界区                         
                //创建开始任务
                OSTaskCreate((OS_TCB         * )&TcpipthreadTaskTCB,                        //任务控制块
                                         (CPU_CHAR        * )"TCPIPThread task",                         //任务名字
                     (OS_TASK_PTR )thread,                                                 //任务函数
                     (void                * )0,                                                        //传递给任务函数的参数
                     (OS_PRIO          )prio,                                             //任务优先级
                     (CPU_STK   * )&TCPIP_THREAD_TASK_STK[0],        //任务堆栈基地址
                     (CPU_STK_SIZE)stacksize/10,                                //任务堆栈深度限位
                     (CPU_STK_SIZE)stacksize,                                        //任务堆栈大小
                     (OS_MSG_QTY  )0,                                                        //任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                     (OS_TICK          )0,                                                        //当使能时间片轮转时的时间片长度,为0时为默认长度,
                     (void           * )0,                                                        //用户补充的存储区
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                     (OS_ERR         * )&err);                                        //存放该函数错误时的返回值
                OS_CRITICAL_EXIT();        //退出临界区
        }
        return 0;
}
#endif /* !NO_SYS */

沙发
二九结狐六体| | 2019-2-27 12:27 | 只看该作者
看得我眼花缭乱

使用特权

评论回复
板凳
wakayi| | 2019-3-8 12:47 | 只看该作者
电脑端网络怎么设置的

使用特权

评论回复
地板
wowu| | 2019-3-8 12:50 | 只看该作者
不太了解 帮楼主顶一下

使用特权

评论回复
5
xiaoqizi| | 2019-3-8 12:52 | 只看该作者
上位机是怎么写的代码

使用特权

评论回复
6
木木guainv| | 2019-3-8 12:56 | 只看该作者
史诗freertos系统呢

使用特权

评论回复
7
指针函数的指针| | 2019-7-15 11:19 | 只看该作者
你他娘的 就会 照搬别人的 教程,这不是 野火的教程么?

使用特权

评论回复
8
liuxiang5119|  楼主 | 2019-7-17 14:28 | 只看该作者
指针函数的指针 发表于 2019-7-15 11:19
你他娘的 就会 照搬别人的 教程,这不是 野火的教程么?

好久不上论坛 难得一见的喷子  大神级别的人物啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

13

主题

124

帖子

4

粉丝