在stm32f103c8t6 上进行无OS移植LWIP

首先,为什么要做无OS的LWIP呢?原因很简单,因为stm32f103c8t6只有20K的RAM,很难支持OS+LWIP。

无OS的LWIP的一个优点是,可以提高单片机的以太网的响应速度。

LWIP的介绍就不说了,网上查一大把。

我的无OS移植LWIP基于ST官网的一个示例:

STSW-STM32026LwIP TCP/IP stack demonstration for STM32F107xx (AN3102)

大家可以到官网下载。

这个示例是运行在stm32f107上面的,如果要运行到stm32f103上,还需要进行一些修改。下面是移植的主要步骤。

1. 从ST官网项目中的lwip-1.3.1目录整个复制到你的项目中

2. 修改文件lwip-1.3.1\port\ethernetif.c,我的网卡是enc28j60,主要修改如下

2.1 添加

uint8_t mac[6] = {0x00, 0xe0, 0x3d, 0xf4, 0xdd, 0xf7};  //网卡的mac地址
uint8_t Tx_Data_Buf[512];  //网卡发送缓冲区
uint8_t Rx_Data_Buf[512];  //网卡接收缓冲区

2.2 修改low_level_init

static void
low_level_init(struct netif *netif)
{
  /* set MAC hardware address length */
  netif->hwaddr_len = ETHARP_HWADDR_LEN;

  /* set MAC hardware address */
  netif->hwaddr[0] =  mac[0];
  netif->hwaddr[1] = mac[1];
  netif->hwaddr[2] =  mac[2];
  netif->hwaddr[3] =  mac[3];
  netif->hwaddr[4] = mac[4];
  netif->hwaddr[5] =  mac[5];

  /* maximum transfer unit */
  netif->mtu = 1500;

  /* device capabilities */
  /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;

    enc28j60_init(netif->hwaddr);
}

2.3 修改low_level_output

static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
  struct pbuf *q;
  unsigned int i = 0;

  #if ETH_PAD_SIZE
  pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif
    
for(q = p; q != NULL; q = q->next) {
    /* Send the data from the pbuf to the interface, one pbuf at a
       time. The size of the data in each pbuf is kept in the ->len
       variable. */
        memcpy(&Tx_Data_Buf[i], (u8_t*)q->payload, q->len); 
                i = i + q->len;
  }

    enc28j60_packet_send(Tx_Data_Buf,i);


#if ETH_PAD_SIZE
  pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
  
  LINK_STATS_INC(link.xmit);

  return ERR_OK;
}

2.4 修改low_level_input

static struct pbuf *
low_level_input(struct netif *netif)
{
  struct pbuf *p, *q;
  u16_t len;
    unsigned int i =0;
  /* Obtain the size of the packet and put it into the "len"
     variable. */
  len = enc28j60_packet_receive( Rx_Data_Buf,512);  
    if(len == 0) return 0;

#if ETH_PAD_SIZE
  len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
#endif

  /* We allocate a pbuf chain of pbufs from the pool. */
  p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);

  if (p != NULL) {

#if ETH_PAD_SIZE
    pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif

    /* We iterate over the pbuf chain until we have read the entire
     * packet into the pbuf. */
    for(q = p; q != NULL; q = q->next) {
      /* Read enough bytes to fill this pbuf in the chain. The
       * available data in the pbuf is given by the q->len
       * variable.
       * This does not necessarily have to be a memcpy, you can also preallocate
       * pbufs for a DMA-enabled MAC and after receiving truncate it to the
       * actually received size. In this case, ensure the tot_len member of the
       * pbuf is the sum of the chained pbuf len members.
       */
                memcpy((u8_t*)q->payload, (u8_t*)&Rx_Data_Buf[i], q->len);

                i = i + q->len;
    }

#if ETH_PAD_SIZE
    pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif

    LINK_STATS_INC(link.recv);
  } else {
    //drop packet();
    LINK_STATS_INC(link.memerr);
    LINK_STATS_INC(link.drop);
  }

  return p;  
}

3. 修改stm32f10x_it.c

添加:

__IO uint32_t LocalTime = 0;

修改SysTick_Handler:

void SysTick_Handler(void)
{
     LocalTime += 1;
}

4. 制作main函数

struct netif netif;
__IO uint32_t TCPTimer = 0;
__IO uint32_t ARPTimer = 0;

void LwIP_Init(void)
{
  struct ip_addr ipaddr;
  struct ip_addr netmask;
  struct ip_addr gw;

  /* Initializes the dynamic memory heap defined by MEM_SIZE.*/
  mem_init();

  /* Initializes the memory pools defined by MEMP_NUM_x.*/
  memp_init();


  IP4_ADDR(&ipaddr, 192, 168, 2, 8);
  IP4_ADDR(&netmask, 255, 255, 255, 0);
  IP4_ADDR(&gw, 192, 168, 2, 1);

  /* - netif_add(struct netif *netif, struct ip_addr *ipaddr,
            struct ip_addr *netmask, struct ip_addr *gw,
            void *state, err_t (* init)(struct netif *netif),
            err_t (* input)(struct pbuf *p, struct netif *netif))
    
   Adds your network interface to the netif_list. Allocate a struct
  netif and pass a pointer to this structure as the first argument.
  Give pointers to cleared ip_addr structures when using DHCP,
  or fill them with sane numbers otherwise. The state pointer may be NULL.

  The init function pointer must point to a initialization function for
  your ethernet netif interface. The following code illustrates it's use.*/
  netif_add(&netif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &ethernet_input);

  /*  Registers the default network interface.*/
  netif_set_default(&netif);


  /*  When the netif is fully configured this function must be called.*/
  netif_set_up(&netif);

}


void LwIP_Periodic_Handle(__IO uint32_t localtime)
{

  /* TCP periodic process every 250 ms */
  if (localtime - TCPTimer >= TCP_TMR_INTERVAL)
  {
    TCPTimer =  localtime;
    tcp_tmr();
  }
  /* ARP periodic process every 5s */
  if (localtime - ARPTimer >= ARP_TMR_INTERVAL)
  {
    ARPTimer =  localtime;
    etharp_tmr();
  }

}


int main()
{
    RCC_Config();
    LwIP_Init();
    SysTick_Config(SystemCoreClock / 1000);
    HelloWorld_init();
  while (1)
  {    
    /* Periodic tasks */
      ethernetif_input(&netif);
      LwIP_Periodic_Handle(LocalTime);
  }
}
5. 修改lwipopts.h文件,因为只有20K的RAM,把一些数改小点,不然编译不通过

#define MEM_SIZE                (10*1024)

#define PBUF_POOL_SIZE          8
#define PBUF_POOL_BUFSIZE       300

#define TCP_MSS                 (300 - 40)

//#define CHECKSUM_BY_HARDWARE 

6. 编译,下载,在cmd命令行里ping和telnet 单片机,运行正常

7. 总结,lwip的无OS移植还是比较简单的,对比UIP的无OS移植,编写应用程序要简单得多。

学习lwip,推荐学习这个https://www.kancloud.cn/jiejietop/tcpip

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值