特殊電子回路株式会社

 

 

特電について

トップ ページ製品情報ブログ「JTAG日記」JTAG情報会社紹介

インデックス

 ボード図面

 クイックスタート

 主な仕様

 GCCの使い方

 ダウンロード

 RXduinoについて

 JTAG ICE

 注文情報

 ご注意

 

サンプルコード

 サンプルコード集

 

RX62N用軽量TCP/IPプロトコルスタック

RX62Nで使える軽量なTCP/IPプロトコルスタックを開発しています。

なぜならば、uIPはあまりにも使い勝手が悪いからです。

 

そこで、uIPでは何ができなかったを洗い出し、下記のような特徴を持ったTCP/IPプロトコルスタックを1から作ることにしました。

 ・Link up/downを検出したら、オートネゴーシエーションとDHCPの再実行をできるようにする。

 ・擬似マルチタスクを使わずに、見通しのよいプログラミングにする

 ・技巧的なマクロを多用しない

 ・任意のポートを使って通信するアプリケーションを作れるようにする

    (つまり、ユーザアプリの中でNTPやTFTPなどを容易に作れるようにする)

 ・コマンドラインから ping や nslookup などを発行できるようにする

 

画面サンプル

現在、開発中のTCP/IPアプリケーションでは、ARPとICMPまで動いています。

pingコマンドでPingを発行することができます。また、PINGに応答することもできます。

 

 

コード(特電HAL用)

このプログラムをビルドする際には、sample/tcpipフォルダに移動して、makeと打ってください。

 

// RX62NのGCCサンプルプログラム
// イーサネット
// (C)Copyright 2011 特殊電子回路

// 使い方
// このプログラムのファイル名をmain.cに変更して、makeしてください。

#include "tkdnip.h"
#include "arp.h"
#include "ip.h"
#include "icmp.h"

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

int g_dump; // パケットダンプの有効/無効

// 送受信バッファをどこに置くか ・・・ SDRAM上
unsigned char *sendpacket = (unsigned char *)0x08000000;
unsigned char *recvpacket = (unsigned char *)0x08001000;

// デフォルトの設定値
unsigned char my_macaddr[6] = {0x02,0x00,0x00,0x00,0x00,0x01};
unsigned char my_ipaddr[4]  = {192,168,1,123};
unsigned char my_ipmask[4]  = {255,255,255,0};
unsigned char gw_ipaddr[4]  = {192,168,1,1};

void packet_dump(unsigned char *buf,int len) {
  int i;
  char tmp[80];
  for(i=0;i<(len + 15)/16;i++) {
    sprintf(tmp,"%04x  ",i*16);
    sci_puts(tmp);
    int j;
    for(j=0;j<16;j++) {
      if(j == 8) sci_puts(" ");
      if(i*16+j >= len) {
        sci_puts("   ");
      }
      else {
        sprintf(tmp,"%02x ",buf[i*16+j]);
        sci_puts(tmp);
      }
    }
    sci_puts(" ");
    for(j=0;j<16;j++) {
      if(j == 8) sci_puts(" ");
      if(i*16+1 >= len) {
        sci_puts(" ");
      }
      else {
        if(isprint(buf[i*16+j])) {
          sprintf(tmp,"%c",buf[i*16+j]);
          sci_puts(tmp);
        }
        else {
          sci_puts(".");
        }
      }
    }
    sci_puts("\n");
  }
}

void check_link()
{
  if(ether_is_linkup()) {
    sci_puts("Link:UP   ");
    if(ether_is_100M()) sci_puts("100M ");
    else                sci_puts("10M  ");

    if(ether_is_fullduplex()) sci_puts("full\n");
    else                sci_puts("half\n");
    
  }
  else {
    sci_puts("Link:DOWN\n");
  }
}

void packet_receive_process()
{
  char tmp[128];
  int rbytes = ether_read(recvpacket);
    
  if(rbytes <= 0) return;
  ethernet_frame_str *ep = (ethernet_frame_str *)recvpacket;

  if(g_dump)
  {
    sprintf(tmp,
      "[Ethernet frame type=%04x received. %d bytes]\n",
    __builtin_rx_revw(ep->type),rbytes);
    sci_puts(tmp);
    packet_dump(recvpacket,rbytes);
  }

   // 何か受信した
  if(ep->type == CONST_REVW(0x0806))
  {
    arp_received(&ep->payload[0],
        rbytes - sizeof(ethernet_frame_str));
    return;
  }

  if(ep->type == CONST_REVW(0x0800))
  {
    ip_headder_str *ip = (ip_headder_str *)&ep->payload[0];
    unsigned long myip = my_ipaddr[0] |
       (my_ipaddr[1] << 8) |
        (my_ipaddr[2] << 16) |
         (my_ipaddr[3] << 24);

    
    if(ip->protocol == PROTO_UDP)
    {
      sprintf(tmp,"[UDP received %d bytes]\n",rbytes);
      sci_puts(tmp);
      return;
    }

    if(ip->protocol == PROTO_ICMP)
    {
      icmp_received(recvpacket,rbytes);
      return;
    }

    if(ip->protocol == PROTO_TCP)
    {
      sprintf(tmp,"[TCP received %d bytes]\n",rbytes);
      sci_puts(tmp);
      packet_dump(recvpacket,rbytes);
      return;
    }

    {
      sprintf(tmp,
        "[Unknown IP packet received %d bytes]\n",rbytes);
      sci_puts(tmp);
      packet_dump(recvpacket,rbytes);
      return;
    }
    return;
  }
  sprintf(tmp,
      "[Unknown ethernet frame %04x received %d bytes]\n",
   __builtin_rx_revw(ep->type),rbytes);
  sci_puts(tmp);
  packet_dump(recvpacket,rbytes);
}

void show_prompt()
{
  sci_puts("RX62N> ");
}

void userapp_ping(unsigned char ipaddr[4])
{
  int i;
  for(i=0;i<4;i++) // 送信回数は4回
  {
    char c;
    send_ping(ipaddr);
    while(g_ping_process)
    {
      // タイムアウト5秒
      if(timer_get_us() - g_ping_timer > 5000000) 
      {
        sci_puts("Request timed out.\n");
        break;
      }
      while((c = sci_getc()) != '\0')
      {
        if(c == 0x03) return;
      }
    }
    timer_wait_ms(1000); // 送信間隔は1000ms
  }
}

unsigned long myrand()
{
  return rand() ^ (rand() << 12) ^ (rand() << 20);
}

void sdram_test()
{
  unsigned int i;
  char tmp[80];
  unsigned long *p;

  sci_puts("SDRAM write..");
  srand(0);
  p = (unsigned long *)0x08000000;
  for(i=0;i<16777216/4;i++)
  {
    *p++ = i;//myrand();
  }
  sci_puts("done\n");

  sci_puts("wait 10 sec\n");
  timer_wait_ms(10000);

  sci_puts("SDRAM read..");
  srand(0);
  p = (unsigned long *)0x08000000;
  for(i=0;i<16777216/4;i++)
  {
    unsigned long val = i;//myrand();
    if(*p != val)
    {
      sprintf(tmp,
        "SDRAM error count=%d read=%08lx write=%08lx\n",
         i,*p,val);
      sci_puts(tmp);
    }
    p++;
  }
  sci_puts("done\n");
  sci_puts("SDRAM test done.\n");
}

void ipconfig()
{
  char tmp[128];
  sprintf(tmp,
     "IP Address. . . . . . . . . . . . : %d.%d.%d.%d\n",
     my_ipaddr[0],my_ipaddr[1],my_ipaddr[2],my_ipaddr[3]);
  sci_puts(tmp);
  sprintf(tmp,
     "Subnet Mask . . . . . . . . . . . : %d.%d.%d.%d\n",
     my_ipmask[0],my_ipmask[1],my_ipmask[2],my_ipmask[3]);
  sci_puts(tmp);
  sprintf(tmp,
     "Default Gateway . . . . . . . . . : %d.%d.%d.%d\n",
     gw_ipaddr[0],gw_ipaddr[1],gw_ipaddr[2],gw_ipaddr[3]);
  sci_puts(tmp);
}

int main() {
  char tmp[128];
  
  sci_init(SCI_SCI0P2x,38400);
  sci_convert_crlf(CRLF_CRLF,CRLF_CRLF); // \nを\r\nに変換
  sci_convert_crlf(CRLF_CRLF,CRLF_CRLF); // \nを\r\nに変換
  
  sci_puts("\nRX62N Ethernet sample program.\n");
  sci_puts("Tokushu Denshi Kairo Inc.\n");
  sprintf(tmp,"Compiled at %s %s\n",__DATE__,__TIME__);
  sci_puts(tmp);
  
  ether_open(my_macaddr);

  // イーサフレームを受信したときに実行される割り込み関数を登録
  ether_regist_user_rx_procedure(packet_receive_process);
  if(!ether_is_linkup()) check_link();

  while(1) {
    if(ether_link_changed()) check_link();

    if(sci_rxcount())
    {
      char cmd[32];
      sci_gets(cmd,32);
      char *tmp = strtok(cmd," ");
      if(tmp)
      {
        if(!strcmp(tmp,"help"))
        {
    sci_puts("COMMAND        Description\n");
    sci_puts("------------------------------------------\n");
    sci_puts("help           Show this message.\n");
    sci_puts("arp -a         Show arp table.\n");
    sci_puts("ipconfig       Show IP configuration\n");
    sci_puts("ping target    Ping the specified target.\n");
    sci_puts("link           Retry link-up and negotiation.\n");
    sci_puts("sdtest         Test SDRAM.\n");
    sci_puts("dump [on|off]  On/Off received packet dump.\n");
      show_prompt();
      continue;
        }

        if(!strcmp(tmp,"link"))
        {
          ether_autonegotiate();
          show_prompt();
          continue;
        }

        if(!strcmp(tmp,"arp"))
        {
          tmp = strtok(NULL," ");
          if(tmp && !strcmp(tmp,"-a"))
          {
            arp_table_show();
          }
          show_prompt();
          continue;
        }

        if(!strcmp(tmp,"sdtest"))
        {
          ether_close();
          sdram_test();
          ether_open(my_macaddr);
          show_prompt();
          continue;
        }

        if(!strcmp(tmp,"ipconfig"))
        {
          ipconfig();
          show_prompt();
          continue;
        }

        if(!strcmp(tmp,"dump"))
        {
          tmp = strtok(NULL," ");
          if(tmp)
          {
            if(!strcmp(tmp,"on")) g_dump = 1;
            if(!strcmp(tmp,"off")) g_dump = 0;
          }
          show_prompt();
          continue;
        }

        if(!strcmp(tmp,"ping"))
        {
          unsigned char ipaddr[4];
          
          do
          {
            tmp = strtok(NULL,".");
            if(!tmp) break;
            ipaddr[0] = atoi(tmp);
          
            tmp = strtok(NULL,".");
            if(!tmp) break;
            ipaddr[1] = atoi(tmp);
          
            tmp = strtok(NULL,".");
            if(!tmp) break;
            ipaddr[2] = atoi(tmp);
          
            tmp = strtok(NULL,"");
            if(!tmp) break;
            ipaddr[3] = atoi(tmp);
  
            userapp_ping(ipaddr);
          }   while(0);
          show_prompt();
          continue;
        }
        sci_puts("Unknwon command ");
        sci_puts(tmp);
        sci_puts("\n");
      }
      show_prompt();
    }
    
  }
}

                        

 

このサンプルの問題点

printfやscanfといった標準ライブラリは、非常に大きなコードとなります。そのため、上記のプログラムをビルドした場合、70kBytesくらいのサイズになってしまい、64kBのRAM容量を超えてしまいます。

 

RX62Nマイコンでは、printfやscanfを使うことはお勧めできません。

 

解決策のひとつはsprintfを使うことです。sprintfを使うと、lowlevel.oをリンクする必要がなくなります。以下のようにscanfを使えば、コードサイズの増加は16KB~32kB程度に抑えられます。

 

char tmp[128];
sprintf(tmp,"count = %04d (%s)\n",count,message);
sci_puts(tmp);

                         

 

戻る

 


Copyright(C) 2011 TokushuDenshiKairo Inc. All rights reserved.