· 

ArduinoのGPIOについて

ArduinoのGPIOはdigitalWriteで上げ下げできる。が、これじゃ満足いかないときがある。

まずはArduinoで、digitalWriteしてみる。

void setup(void){
    pinMode(9,OUTPUT);
    pinMode(10,OUTPUT);
    pinMode(11,OUTPUT);
}
void loop(void){
    digitalWrite(9,HIGH);
    digitalWrite(10,HIGH);
    digitalWrite(11,HIGH);
    digitalWrite(9,LOW);
    digitalWrite(10,LOW);
    digitalWrite(11,LOW);
}

まぁこんな感じで。そすと、

トリガからBまでが26.6usなので、37.6kHz。くそ遅い。それだけでなく、ポート間の遅れが気になります。

測ってみると4.6us遅れています。同時に上げ下げしたいときはこんなんじゃだめです。そこで、よく使われているのが、ArduinoでArduinoらしくない書き方にする方法です。

Arduino本家のDocumentによると、pin9,10,11はPB1,2,3です。Michrochipのデータシートによると、

ということなので、DDRBレジスタでPB1,2,3をセットして、PORTレジスタでPB1,2,3をセットしたりクリアしたりすればいいらしい。

void setup(void){
    DDRB|=0x0E;
}
void loop(void){
    PORTB|=0x0E;
    PORTB&=~0x0E;
}

まぁ、単純にこうしてみる。

そすと、

トリガからBまでが600nsなので、1.67MHz。早くなりました。ポートの上げ下げのタイミングも当然ずれてません。が、Dutyが50%になっていないです。PORTB&=~0x0E;の後、帰ってくるまでに時間がかかるんだろう。タイマーを使えば、スピードは犠牲になるけど、Dutyを合わせることはできるでしょう、、、そんなん知ってる?あぁ、まぁ、はい。Arduino使う人にとっては常識です。すまソ。

 

最近、増えてきつつあるARMを使ったArduinoでどうするか考えてみます。

本家だとArduinoM0, MKR, Due。亜流だと、Seeeduinoあたりが作っているものやSparkfunあたりが作っているものもあります。コード領域、RAMの大きさ、処理速度、ポート電圧等の理由でARMコアのArduinoを選ぶこともあります。

 

まずは普通にdigitalWriteしてみる。

void setup(void){
    pinMode(9,OUTPUT);
    pinMode(10,OUTPUT);
    pinMode(11,OUTPUT);
}
void loop(void){
    digitalWrite(9,HIGH);
    digitalWrite(10,HIGH);
    digitalWrite(11,HIGH);
    digitalWrite(9,LOW);
    digitalWrite(10,LOW);
    digitalWrite(11,LOW);
}

コードは、UNOの時と同じです。

トリガからBまでが9.5usなので、105kHz。UNOで同じコードの時よりは早いっちゃ早い。ポート間の遅れは1.5us、UNOで同じコードの時よりはましだが、、、

では、やはり、Arduinoっぽくない書き方にしてみます。

#define ARDUINO_M0_D00 PORT_PA11
#define ARDUINO_M0_D01 PORT_PA10
#define ARDUINO_M0_D02 PORT_PA08

void setup(void){
    REG_PORT_DIR0=(ARDUINO_M0_D00|ARDUINO_M0_D01|ARDUINO_M0_D02);
    REG_PORT_OUTSET0=(ARDUINO_M0_D00|ARDUINO_M0_D01|ARDUINO_M0_D02);
}
void loop(void){
    REG_PORT_OUTTGL0=(ARDUINO_M0_D00|ARDUINO_M0_D01|ARDUINO_M0_D02);
}

すみません。実験に使用するポートを変えました。9,10,11はたぶんデフォでSERCOMに割り当てられているのか、動かなかったので。MUXを調べるのはめんどい。で、

トリガからBまでが1usなので、1MHz。、、、UNOより遅い。ArduinoM0は48MHz, ArduinoUNOは16MHzで動いているはずなのに、、、ARMって遅いんですかね?

TGR使っているので、Dutyはまともです。

 

で、48MHzで、そんなバカなって思う人がいるようで、SASAPEA'S LABさんという方が「Seeeduino XIAO (ATSAMD21G18) のGPIO速度」という記事で、Cortex®-M0+シングルサイクルIOBUSってのをやってます。

参考にしてやってみます。

ページ内のIOBUS.hをいただいてフォルダ内にぶっこみ、コードはこんな感じで。

#include "IOBUS.h"

#define digitalPinToIOPin(P) ((g_APinDescription[P].ulPort << 5) + g_APinDescription[P].ulPin)
#define PIN_NUM_A5 digitalPinToIOPin(PIN_A5)
#define PIN_NUM_A4 digitalPinToIOPin(PIN_A4)
#define PIN_NUM_A3 digitalPinToIOPin(PIN_A3)

void setup()
{
    IOBUS::pinMode(PIN_NUM_A5, OUTPUT, true);
    IOBUS::pinMode(PIN_NUM_A4, OUTPUT, true);
    IOBUS::pinMode(PIN_NUM_A3, OUTPUT, true);
}

void loop()
{
    IOBUS::digitalWrite(PIN_NUM_A5, HIGH);
    IOBUS::digitalWrite(PIN_NUM_A4, HIGH);
    IOBUS::digitalWrite(PIN_NUM_A3, HIGH);
    IOBUS::digitalWrite(PIN_NUM_A5, LOW);
    IOBUS::digitalWrite(PIN_NUM_A4, LOW);
    IOBUS::digitalWrite(PIN_NUM_A3, LOW);
}

そんで実行してみる。

で、残念ながら速くならんのだよね、、、これが(普通のdigitalWriteよりは速い)。しかも複数ポートの同時制御ができないし。

で、ヘッダーとかほじくりまくってカンでやってみる。

#define ARDUINO_M0_D00 PORT_PA11
#define ARDUINO_M0_D01 PORT_PA10
#define ARDUINO_M0_D02 PORT_PA08

#define REG_PORT_IOBUS_DIR0              (*(RwReg  *)0x60000000U)
#define REG_PORT_IOBUS_DIRCLR0           (*(RwReg  *)0x60000004U)
#define REG_PORT_IOBUS_DIRSET0           (*(RwReg  *)0x60000008U)
#define REG_PORT_IOBUS_DIRTGL0           (*(RwReg  *)0x6000000CU)
#define REG_PORT_IOBUS_OUT0              (*(RwReg  *)0x60000010U)
#define REG_PORT_IOBUS_OUTCLR0           (*(RwReg  *)0x60000014U)
#define REG_PORT_IOBUS_OUTSET0           (*(RwReg  *)0x60000018U)
#define REG_PORT_IOBUS_OUTTGL0           (*(RwReg  *)0x6000001CU)
#define REG_PORT_IOBUS_IN0               (*(RoReg  *)0x60000020U)
#define REG_PORT_IOBUS_CTRL0             (*(RwReg  *)0x60000024U)
#define REG_PORT_IOBUS_WRCONFIG0         (*(WoReg  *)0x60000028U)
#define REG_PORT_IOBUS_PMUX0             (*(RwReg  *)0x60000030U)
#define REG_PORT_IOBUS_PINCFG0           (*(RwReg  *)0x60000040U)

void setup(void){
    REG_PORT_IOBUS_DIR0=(ARDUINO_M0_D00|ARDUINO_M0_D01|ARDUINO_M0_D02);
    REG_PORT_IOBUS_OUTSET0=(ARDUINO_M0_D00|ARDUINO_M0_D01|ARDUINO_M0_D02);
}
void loop(void){
    REG_PORT_IOBUS_OUTTGL0=(ARDUINO_M0_D00|ARDUINO_M0_D01|ARDUINO_M0_D02);
}

まぁ、こんなかんじ。参考ページによりIOBUSのベースアドレスが0x60000000ってことらしいんだけど、読み書き用の定義がなかったので、自分で作成。で、

速くなったが1.4MHz。うー-んなんだろ、、、Microchipのホームページにも情報がない。今日はこのくらいにしておこう。

 

フライドポテト作ってたら巨大な油ハネがおこり、水ぶくれになるほどのいわゆるやけどを負った。料理中に油ハネであちちってなることあっても水ぶくれができるほどになることはこれまでなかったので、だいぶ凹んだ。そしてフテ寝(昼寝)して、今日もほとんど生きていなかった。こうして日々老いて死に近づいていくんだなーっと思うと、若いうちにいろいろチャレンジしなかったことを後悔したりどうでもよかったり。