GD32F4+LWIP+FreeRTOS+网线热插拔处理


前言

上一篇我将GD32F4裸机移植LWIP的过程写出来,这一篇主要在上一篇的代码基础上加入freertos系统。


一、获取上一篇的代码

在这里插入图片描述

二、加入FreeRTOS操作系统

1.在代码中添加.c和.h文件,并在c/c++中添加工程路径。

2.添加FreeRTOSConfig.h文件,该文件从正点原子的freertos工程中找出,并将头文件修改一下。

在这里插入图片描述

3.修改gd32f4xx_it.c文件。

屏蔽void SVC_Handler(void)、void PendSV_Handler(void)中断
修改void SysTick_Handler(void);
代码如下:

extern void xPortSysTickHandler(void);

/**
 * @brief     systick中断服务函数,使用OS时用到
 * @param     ticks: 延时的节拍数
 * @retval    无
 */  
void SysTick_Handler(void)
{
//    HAL_IncTick();
	delay_decrement();
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) /* OS开始跑了,才执行正常的调度处理 */
    {
        xPortSysTickHandler();
    }
}

4.添加sys_arch.c文件。

   添加该文件之后,编译会报错,这个是因为我们没有打开操作系统接口,这时候,需要在lwippopts.h打开有操作系统的接口。

在这里插入图片描述

5.修改ethernetif.c文件

代码如下(修改部分):

/**
 * In this function, the hardware should be initialized.
 * Called from ethernetif_init().
 *
 * @param netif the already initialized lwip network interface structure
 *        for this ethernetif
 */
static void
low_level_init(struct netif *netif)
{
    netif->hwaddr_len = ETHARP_HWADDR_LEN; /* 设置MAC地址长度,为6个字节 */
    /* 初始化MAC地址,设置什么地址由用户自己设置,但是不能与网络中其他设备MAC地址重复 */
    netif->hwaddr[0] = g_lwipdev.mac[0]; 
    netif->hwaddr[1] = g_lwipdev.mac[1]; 
    netif->hwaddr[2] = g_lwipdev.mac[2];
    netif->hwaddr[3] = g_lwipdev.mac[3];   
    netif->hwaddr[4] = g_lwipdev.mac[4];
    netif->hwaddr[5] = g_lwipdev.mac[5];
    
    netif->mtu = 1500; /* 最大允许传输单元,允许该网卡广播和ARP功能 */
    
    /* 创建一个信号量 */
    g_rx_semaphore = xSemaphoreCreateBinary();

    /* 创建处理ETH_MAC的任务 */
    sys_thread_new("eth_thread",
                   ethernetif_input,        /* 任务入口函数 */
                   netif,                   /* 任务入口函数参数 */
                   NETIF_IN_TASK_STACK_SIZE,/* 任务栈大小 */
                   NETIF_IN_TASK_PRIORITY); /* 任务的优先级 */
    
    /* 网卡状态信息标志位,是很重要的控制字段,它包括网卡功能使能、广播 */
    /* 使能、 ARP 使能等等重要控制位 */
    netif->flags = NETIF_FLAG_BROADCAST|NETIF_FLAG_ETHARP|NETIF_FLAG_LINK_UP;   /* 广播 ARP协议 链接检测 */
    
  /* initialize MAC address in ethernet MAC */ 
    enet_mac_address_set(ENET_MAC_ADDRESS0, netif->hwaddr);
  

    /* initialize descriptors list: chain/ring mode */
#ifdef SELECT_DESCRIPTORS_ENHANCED_MODE
    enet_ptp_enhanced_descriptors_chain_init(ENET_DMA_TX);
    enet_ptp_enhanced_descriptors_chain_init(ENET_DMA_RX);
#else

    enet_descriptors_chain_init(ENET_DMA_TX);
    enet_descriptors_chain_init(ENET_DMA_RX);
    
//    enet_descriptors_ring_init(ENET_DMA_TX);
//    enet_descriptors_ring_init(ENET_DMA_RX);  
    
#endif /* SELECT_DESCRIPTORS_ENHANCED_MODE */  

    /* enable ethernet Rx interrrupt */
     int i;
        for(i=0; i<ENET_RXBUF_NUM; i++){ 
            enet_rx_desc_immediate_receive_complete_interrupt(&rxdesc_tab[i]);
        }
    


#ifdef CHECKSUM_BY_HARDWARE
    /* enable the TCP, UDP and ICMP checksum insertion for the Tx frames */
    for(i=0; i < ENET_TXBUF_NUM; i++){
        enet_transmit_checksum_config(&txdesc_tab[i], ENET_CHECKSUM_TCPUDPICMP_FULL);
    }
#endif /* CHECKSUM_BY_HARDWARE */


    /* enable MAC and DMA transmission and reception */
    enet_enable();  
}

/**
 * This function should do the actual transmission of the packet. The packet is
 * contained in the pbuf that is passed to the function. This pbuf
 * might be chained.
 *
 * @param netif the lwip network interface structure for this ethernetif
 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
 * @return ERR_OK if the packet could be sent
 *         an err_t value if the packet couldn't be sent
 *
 * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
 *       strange results. You might consider waiting for space in the DMA queue
 *       to become available since the stack doesn't retry to send a packet
 *       dropped because of memory failure (except for the TCP timers).
 */

static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
static xSemaphoreHandle s_tx_semaphore = NULL;
    struct pbuf *q;
    uint8_t *buffer ;
    uint16_t framelength = 0;
    ErrStatus reval = ERROR;
  
    SYS_ARCH_DECL_PROTECT(sr);
    
    if (s_tx_semaphore == NULL){
        vSemaphoreCreateBinary (s_tx_semaphore);
    }

    if (xSemaphoreTake(s_tx_semaphore, portMAX_DELAY)){    
        SYS_ARCH_PROTECT(sr);
      
        while((uint32_t)RESET != (dma_current_txdesc->status & ENET_TDES0_DAV)){
        }    
        buffer = (uint8_t *)(enet_desc_information_get(dma_current_txdesc, TXDESC_BUFFER_1_ADDR));

        for(q = p; q != NULL; q = q->next){ 
            memcpy((uint8_t *)&buffer[framelength], q->payload, q->len);
            framelength = framelength + q->len;
        }

       /* transmit descriptors to give to DMA */ 
#ifdef SELECT_DESCRIPTORS_ENHANCED_MODE
        reval = ENET_NOCOPY_PTPFRAME_TRANSMIT_ENHANCED_MODE(framelength, NULL);
#else
        reval = ENET_NOCOPY_FRAME_TRANSMIT(framelength);
#endif /* SELECT_DESCRIPTORS_ENHANCED_MODE */

        SYS_ARCH_UNPROTECT(sr);
        
        /* give semaphore and exit */
        xSemaphoreGive(s_tx_semaphore);
    }
    
    if(SUCCESS == reval){
        return ERR_OK;
    }else{
        while(1){
        }
    }
}

/**
 * Should allocate a pbuf and transfer the bytes of the incoming
 * packet from the interface into the pbuf.
 *
 * @param netif the lwip network interface structure for this ethernetif
 * @return a pbuf filled with the received packet (including MAC header)
 *         NULL on memory error
 */
static struct pbuf *
low_level_input(struct netif *netif)
{  
    struct pbuf *p= NULL, *q;
    uint32_t l =0;
    u16_t len;
    uint8_t *buffer;

    /* obtain the size of the packet and put it into the "len" variable. */
    len = enet_desc_information_get(dma_current_rxdesc, RXDESC_FRAME_LENGTH);
    buffer = (uint8_t *)(enet_desc_information_get(dma_current_rxdesc, RXDESC_BUFFER_1_ADDR));
  
    if (len > 0){
        /* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
        p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
    }
  
    if (p != NULL){
        for(q = p; q != NULL; q = q->next){
            memcpy((uint8_t *)q->payload, (u8_t*)&buffer[l], q->len);
            l = l + q->len;
        }
    }
#ifdef SELECT_DESCRIPTORS_ENHANCED_MODE
    ENET_NOCOPY_PTPFRAME_RECEIVE_ENHANCED_MODE(NULL);
  
#else
    
    ENET_NOCOPY_FRAME_RECEIVE();
#endif /* SELECT_DESCRIPTORS_ENHANCED_MODE */

    return p;
}


6.修改以太网中断函数


extern void lwip_pkt_handle(void);   //在lwip_comm.c里面定义
/*!
    \brief      this function handles ethernet interrupt request
    \param[in]  none
    \param[out] none
    \retval     none
*/

void ENET_IRQHandler(void)
{
    if(SET == enet_interrupt_flag_get(ENET_DMA_INT_FLAG_RS))
    {
        lwip_pkt_handle();      /* 处理以太网数据,即将数据提交给LWIP */
    }

       /* clear the enet DMA Rx interrupt pending bits */
    enet_interrupt_flag_clear(ENET_DMA_INT_FLAG_RS_CLR);
    enet_interrupt_flag_clear(ENET_DMA_INT_FLAG_NI_CLR);
}

该处使用的url网络请求的数据。


7.修改lwip_comm.c与main.c文件

这个过程比较简单,按照错误去修改就行,对照正点原子代码去修改。

8.编译下载

完成上述步骤之后,编译无错误无告警。下载到板子后,发现串口打印以下错误。
在这里插入图片描述
经过耐心的查找,发现是中断分组出现了问题,因此在初始化中加入中断分组的初始化。
在这里插入图片描述
但是又出现了新的问题,如下图,
在这里插入图片描述
找到port.c的791行,然后定位是这个configMAX_SYSCALL_INTERRUPT_PRIORITY定义的问题,在FreeRTOSConfig.c文件中修改下面定义。


//#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY         15                  /* 中断最低优先级 */
//#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5                   /* FreeRTOS可管理的最高中断优先级 */
//#define configKERNEL_INTERRUPT_PRIORITY                 ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
//#define configMAX_SYSCALL_INTERRUPT_PRIORITY            ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
//#define configMAX_API_CALL_INTERRUPT_PRIORITY           configMAX_SYSCALL_INTERRUPT_PRIORITY

/* the lowest interrupt priority that can be used in a call to a "set priority" function */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY       0xf

/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions.  Do not call
interrupt safe freertos api functions from any interrupt that has a higher
priority than this! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY   2

/* interrupt priorities used by the kernel port layer itself */
#define configKERNEL_INTERRUPT_PRIORITY                ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY           32 //( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )


9.ping包测试

在这里插入图片描述

总结

移植代码并不难,最重要的是接下来的学习,如何熟练的使用LWIP才是最难的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值