以前の投稿では、STM32F103RC(RAM 48KB)でCDCECMを起動させたのですが、BluePillでNuttxを起動させる場合、TCP/IPを設定する記事はほとんど見あたりません。さらにBluePillにかぎらず、Ethernetアダプタを使わずに複数ターゲットを同時にかつDHCPでアドレスを割り当てネットワーク接続させる記事もみあたらなかったので以前の投稿に加えてトライしてみました。
今回のコンフィグはDHCPでアドレスを取得してPINGに応答するだけでほぼ実用性はありませんが、NuttxをBluePillよりもRAMが多い機種、例えば、RAM 48KのSTM32F103RCやRAM 64KのF401CC/RAM 96KのF401CE/RAM 128KのF411CEでUSB/DHCP接続などで役に立ちそうなので、本稿を備忘録を兼ねてあげてみることにしました。なお、CPUIDの一部をマックアドレスの一部に疑似的に割り当てているので、ネットワークの設定のために個体ごとにconfig・sourceを変更しコンパイルする必要はありません。
早速ですが、コンフィグは以下の様にしてみました。
# # This file is autogenerated: PLEASE DO NOT EDIT IT. # # You can use "make menuconfig" to make any modifications to the installed .config file. # You can then do "make savedefconfig" to generate a new defconfig file that includes your # modifications. # # CONFIG_DISABLE_ENVIRON is not set # CONFIG_DISABLE_POSIX_TIMERS is not set # CONFIG_NSH_DISABLEBG is not set # CONFIG_NSH_DISABLESCRIPT is not set # CONFIG_NSH_DISABLE_DD is not set # CONFIG_NSH_DISABLE_EXEC is not set # CONFIG_NSH_DISABLE_EXIT is not set # CONFIG_NSH_DISABLE_GET is not set # CONFIG_NSH_DISABLE_IFCONFIG is not set # CONFIG_NSH_DISABLE_LOSETUP is not set # CONFIG_NSH_DISABLE_MKRD is not set # CONFIG_NSH_DISABLE_PS is not set # CONFIG_NSH_DISABLE_PUT is not set # CONFIG_NSH_DISABLE_WGET is not set # CONFIG_NSH_DISABLE_XD is not set CONFIG_ARCH="arm" CONFIG_ARCH_BOARD="stm32f103-minimum" CONFIG_ARCH_BOARD_STM32F103_MINIMUM=y CONFIG_ARCH_CHIP="stm32" CONFIG_ARCH_CHIP_STM32=y CONFIG_ARCH_CHIP_STM32F103C8=y CONFIG_ARCH_STACKDUMP=y CONFIG_BOARD_LOOPSPERMSEC=5483 CONFIG_BUILTIN=y CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_SYMBOLS=y CONFIG_DEFAULT_SMALL=y CONFIG_FS_PROCFS=y CONFIG_FS_RAMMAP=y CONFIG_INTELHEX_BINARY=y CONFIG_MAX_TASKS=4 CONFIG_MAX_WDOGPARMS=2 CONFIG_NFILE_DESCRIPTORS=4 CONFIG_NFILE_STREAMS=4 CONFIG_NSH_ARCHINIT=y CONFIG_NSH_BUILTIN_APPS=y CONFIG_NXFLAT=y CONFIG_PREALLOC_MQ_MSGS=4 CONFIG_PREALLOC_TIMERS=0 CONFIG_PREALLOC_WDOGS=4 CONFIG_RAM_SIZE=20480 CONFIG_RAM_START=0x20000000 CONFIG_RAW_BINARY=y CONFIG_RR_INTERVAL=200 CONFIG_SCHED_HPWORK=y CONFIG_SCHED_WAITPID=y CONFIG_SDCLONE_DISABLE=y CONFIG_STDIO_BUFFER_SIZE=0 # CONFIG_STM32_BKP is not set CONFIG_STM32_JTAG_FULL_ENABLE=y # CONFIG_STM32_PWR is not set # CONFIG_STM32_RTC is not set CONFIG_STM32_USART1=y CONFIG_SYMTAB_ORDEREDBYNAME=y CONFIG_SYSTEM_NSH=y CONFIG_TASK_NAME_SIZE=0 CONFIG_USART1_RXBUFSIZE=128 CONFIG_USART1_SERIAL_CONSOLE=y CONFIG_USART1_TXBUFSIZE=128 CONFIG_USER_ENTRYPOINT="nsh_main" CONFIG_WDOG_INTRESERVE=0 CONFIG_USBDEV=y CONFIG_BOARDCTL_USBDEVCTRL=y CONFIG_STM32_USB=y CONFIG_NET=y CONFIG_NET_BROADCAST=y CONFIG_NET_CDCECM=y CONFIG_NET_ICMP=y CONFIG_NET_ICMP_SOCKET=y CONFIG_NET_SOCKOPTS=y CONFIG_NET_TCP=y CONFIG_NET_UDP=y CONFIG_NETDEV_PHY_IOCTL=y CONFIG_NETDEVICES=y CONFIG_NETINIT_DHCPC=y CONFIG_NETINIT_DNS=y CONFIG_NETINIT_NETLOCAL=n CONFIG_NETINIT_NOMAC=y CONFIG_NETINIT_SWMAC=y CONFIG_NETINIT_THREAD=y CONFIG_NETDB_DNSCLIENT=y CONFIG_NETUTILS_DHCPC=y CONFIG_DEFAULT_TASK_STACKSIZE=768 CONFIG_BOARD_INITTHREAD_STACKSIZE=768 CONFIG_BUILTIN_PROXY_STACKSIZE=512 CONFIG_IDLETHREAD_STACKSIZE=512 CONFIG_NETINIT_THREAD_STACKSIZE=768 CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=512 CONFIG_SCHED_HPWORKSTACKSIZE=512 CONFIG_SYSTEM_NSH_STACKSIZE=896 CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=512 CONFIG_PTHREAD_STACK_MIN=512 CONFIG_PTHREAD_STACK_DEFAULT=512 CONFIG_USERMAIN_STACKSIZE=896参考までに、DHCPはUDPで、かつ、BroadCastを必要とするのでCONFIG_UDP=nの設定が使えません。つまり、どうしてもスタックを多量に消費してしまいます。また、STACK SIZEの調整が上手くいかず万事休すかとあきらめかけていたところ、NXFLATとFS_RAMMAPをenableにすることで何とかDHCP接続ができるようになりました。ただし、DNSクライアントの設定をしてはいますが、メモリ不足のため、残念ながらnslookupは今のところ機能していません。(DHCPとUDPをあきらめるとNSLOOKUPを起動させることはできましたが本稿では触れません。) 続いて、boards/arm/stm32/stm32f103-minimum/src/stm32_bringup.cの編集を行います。
# 前略
#ifdef CONFIG_NET_CDCECM
# include <nuttx/usb/cdcecm.h>
# include <net/if.h>
#endif
# 中略
int stm32_bringup(void)
{
# 中略
#ifdef CONFIG_NET_CDCECM
ret = cdcecm_initialize(0, NULL);
if (ret < 0)
{
_err("ERROR: cdcecm_initialize() failed: %d\n", ret);
}
#endif
# 中略
return ret;
}
続いて、drivers/usbdev/cdcecm.cの編集です。こちらはDiff形式で以下の様にしてみました。
$ diff -urN drivers/usbdev/cdcecm.c.orig drivers/usbdev/cdcecm.c
--- drivers/usbdev/cdcecm.c.orig 2020-09-21 00:09:41.000000000 +0900
+++ drivers/usbdev/cdcecm.c 2021-03-07 17:28:24.624785800 +0900
@@ -123,6 +123,12 @@
#define BUF ((struct eth_hdr_s *)self->dev.d_buf)
+#if defined(CONFIG_STM32_STM32F10XX)
+# define ID3 (*(unsigned long *)0x1FFFF7F0)
+#elif defined(CONFIG_STM32_STM32F4XXX)
+# define ID3 (*(unsigned long *)0x1FFF7A18)
+#endif
+
/****************************************************************************
* Private Types
****************************************************************************/
@@ -1337,9 +1343,44 @@
self->config = config;
/* Set client's MAC address */
-
+#if defined(CONFIG_STM32_STM32F10XX) && defined(CONFIG_NETINIT_MACADDR_2)
+ uint8_t mac[6];
+ unsigned long *id3 = (unsigned long *)0x1FFFF7F0;
+ mac[0] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 1)) & 0xff;
+ mac[1] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 0)) & 0xff;
+ mac[2] = (id3[0] >> (8 * 3)) & 0xff;
+ mac[3] = (id3[0] >> (8 * 2)) & 0xff;
+ mac[4] = (id3[0] >> (8 * 1)) & 0xff;
+ mac[5] = (id3[0] >> (8 * 0)) & 0xff;
+ memcpy(self->dev.d_mac.ether.ether_addr_octet,
+ &mac, IFHWADDRLEN);
+#elif defined(CONFIG_STM32_STM32F4XXX) && defined(CONFIG_NETINIT_MACADDR_2)
+ uint8_t mac[6];
+ unsigned long *id3 = (unsigned long *)0x1FFF7A18;
+ mac[0] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 1)) & 0xff;
+ mac[1] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 0)) & 0xff;
+ mac[2] = (id3[0] >> (8 * 3)) & 0xff;
+ mac[3] = (id3[0] >> (8 * 2)) & 0xff;
+ mac[4] = (id3[0] >> (8 * 1)) & 0xff;
+ mac[5] = (id3[0] >> (8 * 0)) & 0xff;
+ memcpy(self->dev.d_mac.ether.ether_addr_octet,
+ &mac, IFHWADDRLEN);
+#else
+#if defined(CONFIG_NETINIT_MACADDR_1) && defined(CONFIG_NETINIT_MACADDR_2)
+ uint8_t mac[6];
+ mac[0] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 1)) & 0xff;
+ mac[1] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 0)) & 0xff;
+ mac[2] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 3)) & 0xff;
+ mac[3] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 2)) & 0xff;
+ mac[4] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 1)) & 0xff;
+ mac[5] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 0)) & 0xff;
+ memcpy(self->dev.d_mac.ether.ether_addr_octet,
+ &mac, IFHWADDRLEN);
+#else
memcpy(self->dev.d_mac.ether.ether_addr_octet,
"\x00\xe0\xde\xad\xbe\xef", IFHWADDRLEN);
+#endif
+#endif
/* Report link up to networking layer */
@@ -1414,7 +1455,18 @@
#endif
case CDCECM_MACSTRID:
- str = "020000112233";
+#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F4XXX)
+ /* Use CPU ID3 as part of pseudo mac address */
+ ;
+ char id3_str[9] ="", mac_str[13]="";
+ sprintf(id3_str, "%08lx", ID3);
+ strcat (mac_str, "0a0e");
+ strcat (mac_str, id3_str);
+ str = mac_str;
+#else
+ str = CONFIG_CDCECM_MACSTRID;
+#endif
+
break;
default:
@@ -2151,8 +2203,44 @@
* Applies only if the Ethernet MAC has its own internal address.
*/
+#if defined(CONFIG_STM32_STM32F10XX) && defined(CONFIG_NETINIT_MACADDR_2)
+ uint8_t mac[6];
+ unsigned long *id3 = (unsigned long *)0x1FFFF7F0;
+ mac[0] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 1)) & 0xff;
+ mac[1] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 0)) & 0xff;
+ mac[2] = (id3[0] >> (8 * 3)) & 0xff;
+ mac[3] = (id3[0] >> (8 * 2)) & 0xff;
+ mac[4] = (id3[0] >> (8 * 1)) & 0xff;
+ mac[5] = (id3[0] >> (8 * 0)) & 0xff;
+ memcpy(self->dev.d_mac.ether.ether_addr_octet,
+ &mac, IFHWADDRLEN);
+#elif defined(CONFIG_STM32_STM32F4XXX) && defined(CONFIG_NETINIT_MACADDR_2)
+ uint8_t mac[6];
+ unsigned long *id3 = (unsigned long *)0x1FFF7A18;
+ mac[0] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 1)) & 0xff;
+ mac[1] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 0)) & 0xff;
+ mac[2] = (id3[0] >> (8 * 3)) & 0xff;
+ mac[3] = (id3[0] >> (8 * 2)) & 0xff;
+ mac[4] = (id3[0] >> (8 * 1)) & 0xff;
+ mac[5] = (id3[0] >> (8 * 0)) & 0xff;
+ memcpy(self->dev.d_mac.ether.ether_addr_octet,
+ &mac, IFHWADDRLEN);
+#else
+#if defined(CONFIG_NETINIT_MACADDR_1) && defined(CONFIG_NETINIT_MACADDR_2)
+ uint8_t mac[6];
+ mac[0] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 1)) & 0xff;
+ mac[1] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 0)) & 0xff;
+ mac[2] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 3)) & 0xff;
+ mac[3] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 2)) & 0xff;
+ mac[4] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 1)) & 0xff;
+ mac[5] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 0)) & 0xff;
+ memcpy(self->dev.d_mac.ether.ether_addr_octet,
+ &mac, IFHWADDRLEN);
+#else
memcpy(self->dev.d_mac.ether.ether_addr_octet,
"\x00\xe0\xde\xad\xbe\xef", IFHWADDRLEN);
+#endif
+#endif
/* Register the device with the OS so that socket IOCTLs can be performed */
なお、コードの通り、STM32F4XXXでもCDCECMのマックアドレスを疑似的にユニークにするようにしています。注意点は、LINUX上で認識されるMACアドレスの上位4桁は、0x0a0eでハードコーディングしていて(MACSTRIDの辺り)、ターゲット上でのデバイスのマックアドレスとは異なるアドレスにしているところです。(同じマックアドレスだと挙動がおかしくなります。)
ほかの変更は以下の通りです。
$ diff -urN ../apps/netutils/netinit/netinit.c.orig ../apps/netutils/netinit/netinit.c --- ../apps/netutils/netinit/netinit.c.orig 2020-09-21 00:09:46.000000000 +0900 +++ ../apps/netutils/netinit/netinit.c 2021-03-06 22:33:47.000000000 +0900 @@ -299,11 +299,24 @@ mac[0] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 1)) & 0xff; mac[1] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 0)) & 0xff; - +#if defined(CONFIG_STM32_STM32F10XX) + unsigned long *pmac = (unsigned long *)0x1FFFF7F0; + mac[2] = (pmac[0] >> (8 * 3)) & 0xff; + mac[3] = (pmac[0] >> (8 * 2)) & 0xff; + mac[4] = (pmac[0] >> (8 * 1)) & 0xff; + mac[5] = (pmac[0] >> (8 * 0)) & 0xff; +#elif defined(CONFIG_STM32_STM32F4XXX) + unsigned long *pmac = (unsigned long *)0x1FFF7A18; + mac[2] = (pmac[0] >> (8 * 3)) & 0xff; + mac[3] = (pmac[0] >> (8 * 2)) & 0xff; + mac[4] = (pmac[0] >> (8 * 1)) & 0xff; + mac[5] = (pmac[0] >> (8 * 0)) & 0xff; +#else mac[2] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 3)) & 0xff; mac[3] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 2)) & 0xff; mac[4] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 1)) & 0xff; mac[5] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 0)) & 0xff; +#endif /* Set the MAC address */
--- drivers/usbdev/Kconfig.orig 2020-09-21 00:09:41.000000000 +0900
+++ drivers/usbdev/Kconfig 2021-01-03 01:38:22.900000000 +0900
@@ -565,6 +565,10 @@
string "Product string"
default "CDC/ACM Serial"
+config CDCACM_SERIALSTR
+ string "CDC ACM SERIALSTR"
+ default "0"
+
endif # !CDCACM_COMPOSITE
endif # CDCACM
@@ -969,6 +973,10 @@
endif # USBDEV_DUALSPEED
+config CDCECM_MACSTRID
+ string "MAC address string"
+ default "020000112233"
+
if !CDCECM_COMPOSITE
# In a composite device the Vendor- and Product-ID is given by the composite
変更は以上です。あとは、コンフィグを流して、コンパイルし、ターゲットに書き込んでください。書き込みは64kbをこえるので、たとえばOpenOCDで書き込む場合、以下の様にcfgファイルを別途作成します。(Flashが128kb内蔵されていないC8T6があるかもしれませんが...)
$ diff -urN /mnt/c/Devz/OCD/share/openocd/scripts/target/stm32f1x.cfg /mnt/c/Devz/OCD/share/openocd/scripts/target/stm32f103c8t6_128k.cfg --- /mnt/c/Devz/OCD/share/openocd/scripts/target/stm32f1x.cfg 2020-02-29 08:52:14.937789600 +0900 +++ /mnt/c/Devz/OCD/share/openocd/scripts/target/stm32f103c8t6_128k.cfg 2021-02-21 07:36:20.130326800 +0900 @@ -1,5 +1,7 @@ # script for stm32f1x family +set FLASH_SIZE 0x20000 + # # stm32 devices support both JTAG and SWD transports. #書き込みはたとえば以下の様にすることができます。
openocd.exe -f interface/cmsis-dap.cfg -f target/stm32f103c8t6_128k.cfg -c "init" -c "reset halt" -c "flash write_image erase nuttx.bin 0x08000000 bin" -c shutdown続いてLinux側の設定ですが、前述同様、注意点があります。一般的なRNDIS/CDCECMと異なり、NuttX on Bluepill での CDCECMでは、ターゲット上でIPアドレスを取得し、Linux上ではターゲット上でのMacアドレスとはことなるMacアドレスを割り当てる必要があります。つまり、Linux上で認識されるCDCECMデバイスにLinux側で認識しているインターフェースのmacアドレスと、同じmacアドレスをターゲットに振るとターゲットにアクセスできません。図にすると分かるのですが、 LINUX --- CDCECM IF --- TARGET IF --- NUTTTX であって、 LINUX --- TARGET_IF --- NUTTX ではありません。 このため、linux側でTARGETをDHCPでアドレスを付与し、複数接続/挿抜する場合などを想定すると、
LINUX | BRIDGE_BR0===CDCECM_IF1---TARGET_IF1---NUTTX1 BRIDGE_BR0===CDCECM_IF2---TARGET_IF2---NUTTX2このようにブリッジを経由した接続であれば、DHCPでTARGET_IFにアドレスを直接割り振り・管理することができます。つまり、bridgeに例えば10.0.0.1を割当てておいて、USB-CDCECMデバイスが接続されるごとに、BRIDGEに接続されるようにします。具体的には以下の様にしました。
#/etc/network/interfaces.d/br0 auto br0 iface br0 inet static pre-up /sbin/brctl addbr br0 address 10.0.0.1 netmask 255.255.255.0 network 10.0.0.0 broadcast 10.0.0.255
#/etc/network/interfaces.d/eth0 auto eth0 allow-hotplug eth0 iface eth0 inet manual pre-up brctl addif br0 eth0 pre-down brctl delif br0 eth0
#/etc/network/interfaces.d/eth1 auto eth1 allow-hotplug eth1 iface eth1 inet manual pre-up brctl addif br0 eth1 pre-down brctl delif br0 eth1なお、ネットワークデバイス名は、カーネル上ではusbXで認識されたり、また、enxUUVVWWXXYYZZのように認識されることがありますが、以前の投稿(追記分)と同様に、udevにてethXで識別できるようにしておきます。
#/etc/udev/rules.d/70-persistent-net.rules
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="0a:0e:51:16:VV:WW", NAME="eth0"
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="0a:0e:51:14:XX:YY", NAME="eth1"
また、dhcpでアドレスを割当てるので、dhcpサーバの設定を以前の投稿と同様に例えば以下の様にしておきます。
#/etc/dhcp/dhcpd.conf
subnet 10.0.0.0 netmask 255.255.255.0 {
range 10.0.0.10 10.0.0.20;
option routers 10.0.0.1;
option domain-name-servers 1.1.1.1, 1.0.0.1;
}
なお、いうまでもありませんが、個体ごとに疑似マックアドレスを持たせているので、dhcpサーバでmacアドレス毎に個別にアドレスを設定することもできます。
基本的には設定は以上です。コンパイル・設定が上手くいっていると、ターゲットが自動でアドレスを取得し、母艦側からターゲットにPINGが通ります。ターゲット上では以下の様になります。
nsh> ifconfig
eth0 Link encap:Ethernet HWaddr 00:e0:87:11:XX:XX at UP
inet addr:10.0.0.16 DRaddr:10.0.0.1 Mask:255.255.255.0
PINGが通るだけですが、RAM20KでTCP/IP+UDP+ICMP+DHCPがとりあえず入るので、他のRAMの多い機種だとかなり自由度が増しそうです。参考までに、STM32F103RCでスタックサイズをデフォルト(無指定)に戻したところ、4k程RAMの消費が増えただけで、nslookupなども起動し、ターゲット間の疎通も確認しています。BluePillももう少しRAMがあればなぁと思いますが、BluePillはユニークなシリアル番号をもったCMSIS-DAPアダプタとして活躍してもらうことになりそうです・・・
今回は以上です。それでは。
コメント
コメントを投稿