ハイスペックマイコン基板Teensy 4.1を使いました。
開発環境の作り方と簡単なベンチマーク評価をしました。
基本的なGPIOや通信機能とNativeEthernetのTCPクライアントでTelnet通信をしました。
マイコン名
簡単紹介
ハイスペックマイコン基板。
LAN接続(別売キット)、TFカードリーダ実装。

PJRC製品ページ(外部サイト) : Teensy® 4.1
ピン配置

外観

使ってみた
◆開発環境
Arduino環境で開発しました。
ArduinoIDEには1.x と 2.x のバージョン系統があります。
今回2.x(動作確認時は2.3.4)での開発しましたが、1.xと比べて環境作成が簡単になり、書き込みもArduino nanoやRP2040搭載基板のようにボードライブラリとシリアルポート番号を設定するだけです。
次の「性能調査」で使ったGPIOの単純Low/High設定スケッチをコンパイルするのにかかった時間は17秒でした。
少し時間がかかりますが、高性能マイコンの中では速いほうだと思います。
◆性能調査
現在Arduino環境で開発できるマイコンボードでは最大クロックが設定できる基板です。
デフォルト設定でも抜群の性能ですが、オーバークロックを設定することでさらに高速処理ができます。
GPIOのOff/Onを繰り返す処理での信号間の時間を測りました。
代表的な基板と比べてもダントツの速度が出ています。
主なマイコン基板との比較です。
Teensy4.1については、OverClock(1008MHz)の結果も併記します。
| 基板名 | CPU | クロック(MHz) | 周期(MHz) |
|---|---|---|---|
| Teensy 4.1(Over Clock) | Coretex M7 | 1008 | 23.81 |
| Teensy 4.1 | Coretex M7 | 600 | 14.493 |
| ESP32 DevkitC V4 | Xtensa LX6 | 240 | 4.2 |
| Raspberry Pi Pico | RP2040 | 125 | 0.74 |
| Arduino nano 328P | ATmega328P | 16 | 0.15 |
オーバークロックにすると発熱があります。
環境が20℃未満であればさほど問題にならないかもしれませんが、ヒートシンクやファンを付けるなど放熱対策があると安心できます。
◆付属機能
Ethernet
基板にはPhyチップが搭載され、Ethernetピンに専用のRJ45(LANコネクタ)を接続することでLAN通信ができます。
今回簡単なTCP/IP通信でTelenet ClientとしてServerと通信しました。
TF Slot(SDカードリーダ)
ネイティブSDカードリーダが搭載されています。
残念ながらライブラリが見つからないので試すことができませんでした。
準備
Arduino環境の作成
◆開発環境
Arduino環境を使用します。
Arduino環境の作成についてはこちらで紹介しています。
◆ボードライブラリ
Arduino IDEのボードマネージャからTeensy用のライブラリのインストールとボードの選択をします。
Arduino IDE2.x からはボードマネージャからインストールができるようになりました。
| ボードマネージャのURL | https://www.pjrc.com/teensy/td_156/package_teensy_index.json |
| 検索 | Teensy |
| ボードライブラリ | Teensy by Paul atoffregen バージョン x.x.x |
| 選択するボード | Teensy > Teensy 4.1 |
◆モジュールライブラリ
I2CのサンプルではSSD1306 OLED、SPIのサンプルではILI9341を使用します。
サンプルを使用しない場合はインストール不要です。
SSD1306
I2Cを使ったOLED(SSD1306)を使用する場合にインストールします。
| ライブラリ名 | 検索 | 確認時のバージョン |
|---|---|---|
| Adafruit SSD1306 by Adafruit | SSD1306 | 2.5.11 |
| Adafruit GFX Library by Adafruit | GFX | 1.11.10 |
ILI9341
SPIを使ったLCD(ILI9341)を使用する場合にインストールします。
| ライブラリ名 | 検索 | 確認時のバージョン |
|---|---|---|
| Adafruit ILI9341 by Adafruit | ILI9341 | 1.6.1 |
| Adafruit GFX Library by Adafruit | GFX | 1.11.10 |
XPT2046 or HR2046
SPIを使ったタッチパネル(XPT2046または互換品HR2046)を使用する場合にインストールします。
| ライブラリ名 | 検索 | 確認時のバージョン |
|---|---|---|
| XPT2046_Touchscreen by Paul Stoffregen | XPT2046 | 1.4 |
NativeEthernet library
Ethernet Kit for Teensy4.1を使う場合にインストールします。
このライブラリは「PJRC Store」からライブラリをダウンロードし、ArduinoIDEの「Add Zip Library…」からインストールします。
PJRC Store : PJRC Store

組み立て
◆Ethernet Kit for Teensy4.1
この作業は「Ethernet Kit for Teensy4.1」を使用する場合に行います。
組み立て前の図を撮影していなかったので、組み立て後の画像で説明します。
キットには、フラットケーブルとピンヘッダ、RJ45コネクタ、コンデンサと子基板が含まれます。
半田付けの作業が必要ですが部品も大きく、取り付け方向の間違いも無いと思います。
Teensy4.1本体には6ピンパラレルピンヘッダの取り付けをします。(赤丸箇所)

コンパイルと書き込み
ArduinoIDEの書き込みボタンからコンパイルと書き込みができます。
他のマイコン基板と違い、Teensyローダを起動してから書き込みを行います。
画面にTeensyローダ画面が表示されますが、自動で行ってくれるため気にする必要はありません。

スケッチ
GPIOデジタル出力
説明
GPIOのデジタル出力を使います。
GPIO0のLowとHighを繰り返し信号の周期を計測します。
計測にはオシロスコープ(HDS272)を使い、信号の立ち上がりから次の立ち上がり(または立下りから次の立下り)の時間を計測します。
単純なスケッチですがコンパイルにかかった時間をストップウォッチで計測します。
配線
GPIO0とGNDをオシロスコープでプローブします。
スケッチ
#define IO_PIN (0)
void setup()
{
pinMode(IO_PIN, OUTPUT);
}
void loop()
{
while(1)
{
digitalWrite(IO_PIN, HIGH);
digitalWrite(IO_PIN, LOW);
}
}
結果
このサンプルスケッチをコンパイルするのにかかった時間は17秒でした。
LowとHighの計測結果です。
波形画像はクロック設定600MHz(デフォルト)と1008Mhz(OverClock)です。

Teensy4.1で設定できるCPUの設定クロックは11設定あります。
全ての計測結果は以下の表です。
| 設定クロック(MHz) | Low/High計測時間(ns) | 周期変換(MHz) |
|---|---|---|
| 24 | 1744 | 0.573 |
| 150 | 278 | 3.597 |
| 396 | 107 | 9.346 |
| 450 | 94 | 10.638 |
| 528 | 79 | 12.658 |
| 600 | 67 | 14.493 |
| 720 | 60 | 16.667 |
| 816 | 51 | 19.608 |
| 912 | 46 | 21.739 |
| 960 | 44 | 22.727 |
| 1008 | 40 | 23.810 |
PWM出力
Teensy4.1のPWMを使います。
PWMの出力信号をオシロスコープ(HDS272)で周期とDutyの変化の様子をモニタします。
スケッチは設定するDutyをあらかじめテーブルで用意し、1秒ごとにテーブルのインデックスを変化させます。
テーブルに用意するDutyは25%, 50%, 75%です。
配線
配線は不要です。
PWMの信号をオシロスコープでモニタするために、GPIO0とGNDをプローブします。
スケッチ
#define PWM_PIN (0)
void setup()
{
int16_t tblPWM[] = {(0xff * 0.25), (0xff * 0.50), (0xff * 0.75)};
int16_t tableCount = sizeof(tblPWM) / sizeof(int16_t);
pinMode(PWM_PIN, OUTPUT);
while(1)
{
for(int16_t i = 0; i < tableCount; i ++)
{
analogWrite(PWM_PIN, tblPWM[i]);
delay(1000);
}
}
}
void loop()
{
}結果
PWMの周期を測ると1周期224usでした。
1秒間の振幅周波数は約4.46kHzです。

1秒ごとにDutyを25%ずつ変化させた結果です。
スケッチ通りに変化している様子がわかります。

アナログ入力(ADC)
説明
Teensy4.1のADCを使います。
Teensy4.1のADCは0~3.3Vの入力を10bit(0 ~ 1023)で読み取ります。
ADCはA0(GPIO14)に0から3.3Vまで約2秒で上昇し、3.3Vから0Vまで約2秒で下降する電圧を入力します。
読み取った値を電圧にしてシリアル出力します。
ADC読み取り値0を0V、ADC読み取り値1023を3.3Vとして一次関数の係数にします。
傾き = 0.00323, 切片 = 0.0
配線

スケッチ
#define ADC (A0)
#define C_A (0.00323f)
#define C_B (0.0)
void setup()
{
Serial.begin(115200);
pinMode(ADC, INPUT);
}
void loop()
{
int16_t iADC = analogRead(ADC);
float fVoltage = (iADC * C_A) + C_B;
Serial.printf("[ADC, Voltage] = [%d, %f]\r\n", iADC, fVoltage);
delay(2);
}結果
実際に入力した最大電圧は3.1V程度でした。
読み取った値は電圧の変化に対してリニアでしたが、3.1V付近での読み取り値はADCで1020。
若干大きめに読み取れているようです。
ADC読み取りの様子です。
画像左下はXIAO SAMD21から入力した電圧、右下は読み取ったシリアル出力された電圧をグラフにしたものです。

UART
UARTで使えるピン
Teensy 4.1ではUSBシリアル以外にも8ポートのUARTを使用できます。
UARTに使用するピンを変更できません。
UARTとUARTオブジェクト、ピンの関係をまとめました。
(ポート名は仮称とします)
| ポート(仮称) | オブジェクト名 | GPIOピン |
|---|---|---|
| USBシリアル | Serial | (USBコネクタ) |
| UART1 | Serial1 | TX(1), RX(0) |
| UART2 | Serial2 | TX(8), RX(7) |
| UART3 | Serial3 | TX(14), RX(15) |
| UART4 | Serial4 | TX(17), RX(16) |
| UART5 | Serial5 | TX(20), RX(21) |
| UART6 | Serial6 | TX(24), RX(25) |
| UART7 | Serial7 | TX(29), RX(28) |
| UART8 | Serial8 | TX(35), RX(34) |
説明
Teensy 4.1でUARTを使います。
8ポートあるUARTのうち1ポート(UART1)とUSBシリアルを使います。
UARTのUARTシリアル変換にはFT232RLを使用しました。
USBシリアルの入力電文はUSBシリアルにオウム返しします。
UART1の入力電文はUART1にオウム返しします。
配線

スケッチ
void setup()
{
Serial.begin(115200);
Serial1.begin(115200);
}
void loop()
{
if(Serial.available() != 0)
{
Serial.write(Serial.read());
}
if(Serial1.available() != 0)
{
Serial1.write(Serial1.read());
}
}
結果
結果を確認するためにTeratermを2つ起動します。
どちらもローカルエコーはONです。
1つはシリアルUSBでCOM36で認識されました。
UART変換モジュール(FT232RL)はCOM8で認識されました。
COM36側に”hellow”と入力すると1文字ごとに返答があるため”hheellllooww”と表示されました。
同じようにCOM8側に”teensy”と入力すると1文字ごとに返答があり”tteeeennssyy”と表示されました。

I2C(SSD1306)
説明
Teensy 4.1 のI2Cを2ポート使い、OLED(SSD1306)を2個使いします。
処理内容はバウンドボールで、ボールが壁に当たるたびに速度を変えて反転します。
OLEDは個々に制御していますが、2つの画面がつながっているように演出しています。
個々にOLEDを制御するためのライブラリはそれぞれにDisplay1とDisplay2オブジェクトを用意します。
左側の画面は(0, 0)から(127, 63)の範囲を表示、右側の画面は(128, 0)から(255, 63)の範囲を表示します。
Adafruitの描画ライブラリは表示範囲外の表示はしないようです。
左側の画面はボールの座標そのものを使うことで左画面の表示範囲にいるうちは表示されます。
右側の画面はボールの座標を画面幅分を引くことで(128, 0)から(255, 63)に見えるようにオフセットしています。
配線

スケッチ
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH (128)
#define SCREEN_HEIGHT (64)
#define OLED_RESET (-1)
#define SCREEN_ADDRESS (0x3C)
Adafruit_SSD1306 display1(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display2(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire1, OLED_RESET);
void setup()
{
const int16_t rnd = 5;
const int16_t radius = 2;
int16_t x = 0;
int16_t y = 0;
int16_t dirx = 1;
int16_t diry = 1;
if(!display1.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
for(;;);
}
display1.clearDisplay();
if(!display2.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
for(;;);
}
display2.clearDisplay();
display1.setTextSize(1);
display1.setTextColor(SSD1306_WHITE);
display2.setTextSize(1);
display2.setTextColor(SSD1306_WHITE);
while(1)
{
display1.clearDisplay();
display2.clearDisplay();
x += dirx;
y += diry;
if((x + dirx) < 0) dirx = (random(rnd) + 1);
if((y + diry) < 0) diry = (random(rnd) + 1);
if((x + dirx) > (SCREEN_WIDTH * 2)) dirx = -(random(rnd) + 1);
if((y + diry) > SCREEN_HEIGHT) diry = -(random(rnd) + 1);
display1.fillCircle(x, y, radius, SSD1306_WHITE);
display2.fillCircle((x - SCREEN_WIDTH), y, radius, SSD1306_WHITE);
display1.display();
display2.display();
}
}
void loop()
{
}結果
SPI(ILI9341 & XPT2046)
説明
Teensy 4.1 のSPIを2ポート使い、LCD(ILI9341)とタッチパネル(XPT2046)を使います。
通常各SPIモジュールのCSを使い分けることによりSPIは1ポートで制御すると思います。
TeensyにはSPIが2ポートあるのでそれぞれを別々の役割で使ってみます。
スケッチの内容はタッチした箇所に白ドットを描画する簡単なペイントツールです。
LCDのスクリーン解像度とタッチパネルの解像度に違いがあるので、タッチパネルの反応座標はLCD座標にリスケーリングしています。
解像度以外に若干のオフセットがあるので現物合わせで調整しています。
配線

スケッチ
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <XPT2046_Touchscreen.h>
#include <SPI.h>
#define LCD_WIDTH (320)
#define LCD_HEIGHT (240)
#define TOUCH_WIDTH_ADJUST (300)
#define TOUCH_HEIGHT_ADJUST (300)
#define TOUCH_WIDTH (4000 - TOUCH_WIDTH_ADJUST)
#define TOUCH_HEIGHT (4000 - TOUCH_HEIGHT_ADJUST)
#define TOUCH_OFFSET_X (150)
#define TOUCH_OFFSET_Y (150)
#define RADIUS (2)
#define TOUCH_CS (0)
#define TFT_DC (3)
#define TFT_CS (10)
#define TFT_RST (2)
XPT2046_Touchscreen ts(TOUCH_CS);
Adafruit_ILI9341 tft = Adafruit_ILI9341(&SPI, TFT_DC, TFT_CS, TFT_RST);
void setup()
{
tft.begin();
tft.setRotation(1);
tft.setTextSize(2);
tft.fillScreen(ILI9341_BLACK);
SPI1.begin();
ts.begin(SPI1);
ts.setRotation(3);
}
void loop()
{
boolean bTouch = ts.touched();
const float RateX = (float)LCD_WIDTH / (TOUCH_WIDTH - TOUCH_OFFSET_X);
const float RateY = (float)LCD_HEIGHT / (TOUCH_HEIGHT - TOUCH_OFFSET_Y);
if (ts.touched() == true)
{
TS_Point tPoint = ts.getPoint();
int16_t x = (float)(tPoint.x - TOUCH_OFFSET_X) * RateX;
int16_t y = (float)(tPoint.y - TOUCH_OFFSET_Y) * RateY;
tft.fillCircle(x, y, RADIUS, ILI9341_WHITE);
}
delay(10);
}
結果
SPIはLCD描画用、SPI1はタッチパネルの読み取り用に使用しました。
タッチした位置をドットペイントすることでメモ帳のように書き込むことができました。
使用したLCDのタッチドライバの調子がイマイチで、座標情報に振れ幅があるのであまりきれいに描けていませんが、状態の良いものを使うときれいな線が描けます

Ethernet(TCP Client)
説明
Teensy 4.1 のEthernetを使います。
別売(またはセット販売)されているEthernet Kit for Teensy4.1を使いTelnetClientで通信します。
使用するスケッチは、「PJRC」から提供されている「Native Ethernet library」のサンプルスケッチを使用します。
ライブラリの入手とインストール方法はこちら。
Ethernet接続先のTelnetServerにはWiznetの「W5100S-EVB-Pico」を使います。
こちらを使った記事とTelnetServerの記事は後日公開します。
サーバー側(W5100S-EVB-Pico)の動作はTelnetで読み取った情報をオウム返しします。
クライアント側(Teensy 4.1)はCOMから読み取った情報をTelnetで送信し、Telnetから受信した情報をCOMに送信します。
配線
ジャンパワイヤによる配線はありません。

スケッチ
「Native Ethernet library」のサンプルスケッチを使用します。
メニュー > Examples > NativeEthernet > TelnetClient
スケッチを修正します。
修正箇所は3か所です。
1.28行目 クライアント側(Teensy4.1)のIPアドレスを設定。
2.31行目 サーバ側(W5100S-EVB-Pico)のIPアドレスを設定。
3.74行目 サーバ側(W5100S-EVB-Pico)の接続ポート番号を設定。
クライアント側のIPアドレスを192.168.1.10としました。
サーバ側のIPアドレスを192.168.1.20、ポート番号を5000としました。
(サーバ側のスケッチ内でサーバのIPアドレスとポートを固定しています)

結果
動作の確認のためにTeraterm(ローカルエコーOn)を起動します。
(サーバー側のTeratermは不要です)
Teratermから文字を入力すると同じ文字が返答されます。
ローカルエコーがOnなので入力した文字と返答された文字が2つずつ表示されました。




コメント