STM32F103を使ってみる

Ethernetライブラリ


Maple CoreにはF103シリーズ用にこ れらのライブラリが含まれていて、この中に2つのEthernetライブラリが有ります。
残念ながらST Coreではこれらのライブラリを使うことができません。
ST CoreでEthernetを使うためにはF407の様にCPU本体にEthernet機能が含まれているものに限られます。



最初にこちらの Ethernet_STMライブラリを使ってみました。
このライブラリはW5x00シリーズのチップに対応しています。
W5x00シリーズにはW5100/W5200/W5500などのチップが有り、これらを使ったモジュールとしては
W5100とW5500のモジュールが安価で入手できます。




どちらもSPI-IFのモジュールで、ピン数はどちらも8ピン仕様ですが、W5100は5V専用、W5500は3.3V/5V兼用となっていま す。
こ ちらにSTM32F103(48ピン)のピンスペックが公開されています。
Level列がFTとなっているピンは5Vトレラントです。
SPIで使うPA4-PA7は5Vトレラントではないので、5VのSPIモジュールを使うときは、MISOをレベルシフトする必要が有ります。
そこで、3.3V仕様のW5500を使ってみました。

Ethernet_STMライブラリは使用するモジュールに応じて、ライブラリヘッダーの変更が必要ですが、
W5500がデフォルトとなっているので、ライブラリヘッダーの変更は不要です。
W5500モジュールとの結線は以下の様になります。
STM32F103 W5500 STM32F103
3.3V(※1) 3.3V 5V
PA6 MISO GND GND
PA7 MOSI RST (※2)
PA4 SS INT
PA5 SCLK N/C

(※1)
Blue Pill/Black Pillに実装されている5V→3.3VのレギュレータはRT9193-33(400mA) です。
W5500はこ ちらのデータシートによるとSupply Currentが132mAとなっていますが、
STM32本体に5V2A以上のUSB電源を供給しないと、安定して動きません。

(※2)
RSTピンはPullUpしておく必要があります。これをしないと安定して動きません。
こちらの 資料の「5.3.13 NRST ピン特性」によると、NRSTポートはプルア ッ プされているので、
しばらくNRSTポートに繋いでいましたが、4.7KΩぐらいでPullUpした方が安定して動きました。
DHCPに接続できないときはRSTピンを一瞬、GNDに落としてやると繋がります。

以下のスケッチでDHCPへの接続を確認する事ができます。
/*
 STM32F103 W5X00 Ethernet Library DHCP test.

 PIN Connections (Using STM32F103):

   W5X00  -  STM32F103
   ---------------------
   VCC    -  3.3V
   GND    -  GND
   SS     -  Pin PA4
   SCLK   -  Pin PA5
   MISO   -  Pin PA6
   MOSI   -  Pin PA7
   RST    -  PullUp
*/

#include <SPI.h>
#include <Ethernet_STM.h>   // https://github.com/rogerclarkmelbourne/Arduino_STM32

EthernetClient client;

#if defined(WIZ550io_WITH_MACADDRESS) // Use assigned MAC address of WIZ550io
;
#else
#if defined(W5100_ETHERNET_SHIELD)
  byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x51 };
#else
  byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x55 };
#endif
#endif


void setup() {
  Serial.begin(9600);
  while(!Serial);
#if defined(W5100_ETHERNET_SHIELD)
  Serial.println("W5100_ETHERNET_SHIELD begin....");
#endif

#if defined(W5500_ETHERNET_SHIELD)
#if defined(WIZ550io_WITH_MACADDRESS)
  Serial.println("WIZ550io_ETHERNET_SHIELD begin....");
#else
  Serial.println("W5500_ETHERNET_SHIELD begin....");
#endif
#endif

#if defined(WIZ550io_WITH_MACADDRESS)
  if (Ethernet.begin() == 0) {
#else
  if (Ethernet.begin(mac) == 0) {
#endif 
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }
   
  Serial.print("localIP: ");
  Serial.println(Ethernet.localIP());
  Serial.print("subnetMask: ");
  Serial.println(Ethernet.subnetMask());
  Serial.print("gatewayIP: ");
  Serial.println(Ethernet.gatewayIP());
  Serial.print("dnsServerIP: ");
  Serial.println(Ethernet.dnsServerIP());

  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    if (thisByte != 3) Serial.print("-");
  }
  Serial.println();
 
#if defined(WIZ550io_WITH_MACADDRESS)
  byte mac_address[6] ={0,};
  W5100.getMACAddress(mac_address);
  Serial.print("MAC: ");
  for(int i = 0; i < 6; i++) {
    Serial.print("0x");
    Serial.print(mac_address[i],HEX);
    Serial.print(" ");
  }
  Serial.println();
#endif


}

void loop() {
}

シリアルモニターには以下の様に表示されます。




W5500チップを使ったWIZ550ioというMACアドレスを記憶できるモジュールを入手しました。
モジュールの詳細はこちらで紹介して いますが、ボード上に実装されているPICマイコンにMACアドレスが書き込まれています。


PICマイコンに書かれているMACアドレスをしない場合は、上で紹介しているW5500モジュールと同じように使えます。
PICマイコンのMACアドレスを利用するためには、以下のファイルを一部変更します

{Arduino-IDEインストールフォルダー}\hardware\Arduino_STM32-master\STM32F1 \libraries\Ethernet_STM\src\utility\w5100.h

赤文字のdefineを有効にします。
/*
 * Copyright (c) 2013 by WIZnet <support@wiznet.co.kr>
 *
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of either the GNU General Public License version 2
 * or the GNU Lesser General Public License version 2.1, both as
 * published by the Free Software Foundation.
 */

#ifndef    W5100_H_INCLUDED
#define    W5100_H_INCLUDED

#include <SPI.h>

typedef uint8_t SOCKET;

//#define W5100_ETHERNET_SHIELD // Arduino Ethenret Shield and Compatibles ...
//#define W5200_ETHERNET_SHIELD // WIZ820io, W5200 Ethernet Shield
#define W5500_ETHERNET_SHIELD   // WIZ550io, ioShield series of WIZnet

#if defined(W5500_ETHERNET_SHIELD)
#define WIZ550io_WITH_MACADDRESS // Use assigned MAC address of WIZ550io
#include "utility/w5500.h"
#endif


これで、スケッチ内でMACアドレスを指定しなくても、PICマイコンのMACアドレス(モジュールに貼られているシールに記載のMACアドレ ス)が自動的に使われます。
但し、半分ぐらいの確率でDHCPに接続できません。


こ ちらにこの製品のWiKiページが有りますが、RSTピンに関して以下の様に書かれています。
Reset: Low activity
This pin is to initialize WIZ550io.
Hold at least 500us after asserted to LOW and wait for at least 150ms after it is changed to HIGH until WIY550io configured itself.
おそらく、NRSTのLOW/HIGH切り替えタイミングに起因するのだと思います。



一番上の写真にあるW5100モジュールを試してみました。
W5100を使うためには、以下のファイルを一部変更します

{Arduino-IDEインストールフォルダー}\hardware\Arduino_STM32-master\STM32F1 \libraries\Ethernet_STM\src\utility\w5100.h

赤文字のdefineを有効にして、青字のdefineをコメントアウトします。
/*
 * Copyright (c) 2013 by WIZnet <support@wiznet.co.kr>
 *
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of either the GNU General Public License version 2
 * or the GNU Lesser General Public License version 2.1, both as
 * published by the Free Software Foundation.
 */

#ifndef    W5100_H_INCLUDED
#define    W5100_H_INCLUDED

#include <SPI.h>

typedef uint8_t SOCKET;

#define W5100_ETHERNET_SHIELD // Arduino Ethenret Shield and Compatibles ...
//#define W5200_ETHERNET_SHIELD // WIZ820io, W5200 Ethernet Shield
//#define W5500_ETHERNET_SHIELD   // WIZ550io, ioShield series of WIZnet

#if defined(W5500_ETHERNET_SHIELD)
//#define WIZ550io_WITH_MACADDRESS // Use assigned MAC address of WIZ550io
#include "utility/w5500.h"
#endif



これで、W5100を使うことができます。
W5100モジュールとの結線は以下の様になります。
STM32F103 W5100 STM32F103
GND GND 5V 5V(※1)
NRST(※3) RST NSS PA4
PA5 SCK MO PA7
PA6(※2) MI GND GND

POE+ POE-

(※1)
STM32本体に5V2A以上のUSB電源を供給しないと、安定して動きません。

(※2)
STM32F103のGPIO入力のロジックレベルは3.3Vですが、一部のピンは5V Tolerantです。
5V Tolerantピンの一覧はこち らに有ります。
MI(MISO)として使用するPA6は5V Tolerantではないので、
W5100を5Vで駆動した場合、このラインには5V信号が飛び込んでくるので、抵抗でレベルシフトする必要が有ります。

(※3)
RSTピンはNRSTポートに繋がないと動きません。

W5500と同じスケッチが使えます。
W5500は電源LEDしかありませんが、W5100はTX/RXのLEDが有り、送受信していることが良く分かります。




こ ちらのSerasidis_EtherCard_STMライブラリを使ってみました。
このライブラリはENC28J60のチップに対応しています。
ENC28J60のモジュールには5V仕様の物と、3.3V仕様の物が有ります。
左:3.3V仕様 右:5V仕様


5V仕様の物は裏にAMS1117のレギュレータが実装されていて、チップ本体は3.3Vで動いています。


今回は3.3V仕様のモジュールを使いました。
ENC28J60モジュールとの結線は以下の様になります。
STM32F103 ENC28J60 STM32F103
GND GND VCC 3.3V(※1)
(※2) RST CS PA4
PA5 SCK SI PA7
PA6 SO WCL

INT CLKOUT

(※1)
Blue Pill/Black Pillに実装されている5V→3.3VのレギュレータはRT9193-33(400mA) です。
ENC28J60はこ ちらのデータシートによるとOperating Currentが180mAとなっています。

(※2)
RSTピンはPullUpしておく必要があります。これをしないと安定して動きません。
NRSTポートの有るボードでは、NRSTポートに接続し、NRSTポートのないボードでは、適当な抵抗でPullUpしてください。
DHCPに接続できないときはRSTピンを一瞬、GNDに落としてやると繋がります。

ファイル→スケッチ例→Serasidis_EtherCard_STM→testDHCPを動かしましたが、一発でDHCPに繋がりました。




こち らにSTM32のUnique device IDを取り出すコードが公開されています。
W5x00もENC28J60もMACアドレスをスケッチ内で指定する必要が有りますが、複数のSTMでEthernetを使う場合、
書き込むごとにMACアドレスを変える必要が有ります。

そこで、STM32のUnique device IDを利用してMACアドレス(6バイト)の末尾4バイトを、Unique device IDの一部で置き換えてみました。
以下のスケッチでSTM32のUnique device IDと、そこから作成したMACアドレスを確認する事ができます。
/*
 STM32F103 W5X00 Ethernet Library DHCP test.

 PIN Connections (Using STM32F103):

   W5X00  -  STM32F103
   ---------------------
   VCC    -  3.3V
   GND    -  GND
   SS     -  Pin PA4
   SCLK   -  Pin PA5
   MISO   -  Pin PA6
   MOSI   -  Pin PA7
   RST    -  PullUp
*/

#include <SPI.h>
#include <Ethernet_STM.h>   // https://github.com/rogerclarkmelbourne/Arduino_STM32

#define DEBUG 1

EthernetClient client;

#if defined(WIZ550io_WITH_MACADDRESS) // Use assigned MAC address of WIZ550io
;
#else
//byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x51 };
byte mac[] = { 0xDE, 0xAD, 0x00, 0x00, 0x00, 0x00 };
#endif

void setUniqueMAC(byte * mac) {
  delay(1000);
  uint16 *idBase0 =  (uint16 *) (0x1FFFF7E8);
  uint16 *idBase1 =  (uint16 *) (0x1FFFF7E8+0x02);
  uint32 *idBase2 =  (uint32 *) (0x1FFFF7E8+0x04);
  uint32 *idBase3 =  (uint32 *) (0x1FFFF7E8+0x08);

#if DEBUG
  Serial.print("Unique ID is ");
  Serial.print(*(idBase0),HEX);
  Serial.print("-");
  Serial.print(*(idBase1),HEX);
  Serial.print("-");
  Serial.print(*(idBase2),HEX);
  Serial.print("-");
  Serial.println(*(idBase3),HEX);
#endif

//  mac[0] = (*(idBase0) & 0xFF00) >> 8;
//  mac[1] = (*(idBase0) & 0xFF);
  mac[2] = (*(idBase2) & 0xFF000000) >> 24;
  mac[3] = (*(idBase2) & 0xFF0000) >> 16;
  mac[4] = (*(idBase2) & 0xFF00) >> 8;
  mac[5] = (*(idBase2) & 0xFF);
}

void setup() {
  Serial.begin(9600);
  while(!Serial);
  setUniqueMAC(mac);
  for(int i=0;i<6;i++) {
    Serial.print(mac[i],HEX);
    if (i != 5) Serial.print("-");
  }
  Serial.println();
 

#if defined(W5100_ETHERNET_SHIELD)
  Serial.println("W5100_ETHERNET_SHIELD begin....");
#endif

#if defined(W5500_ETHERNET_SHIELD)
#if defined(WIZ550io_WITH_MACADDRESS)
  Serial.println("WIZ550io_ETHERNET_SHIELD begin....");
#else
  Serial.println("W5500_ETHERNET_SHIELD begin....");
#endif
#endif

#if defined(WIZ550io_WITH_MACADDRESS)
  if (Ethernet.begin() == 0) {
#else
  if (Ethernet.begin(mac) == 0) {
#endif 
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }
   
  Serial.print("localIP: ");
  Serial.println(Ethernet.localIP());
  Serial.print("subnetMask: ");
  Serial.println(Ethernet.subnetMask());
  Serial.print("gatewayIP: ");
  Serial.println(Ethernet.gatewayIP());
  Serial.print("dnsServerIP: ");
  Serial.println(Ethernet.dnsServerIP());

  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    if (thisByte != 3) Serial.print("-");
  }
  Serial.println();
 
#if defined(WIZ550io_WITH_MACADDRESS)
  byte mac_address[6] ={0,};
  W5100.getMACAddress(mac_address);
  Serial.print("MAC: ");
  for(int i = 0; i < 6; i++) {
    Serial.print("0x");
    Serial.print(mac_address[i],HEX);
    Serial.print(" ");
  }
  Serial.println();
#endif


}

void loop() {
}

Unique device IDの3オクテット目をMACアドレスの一部として使います。


続く...