« ラズパイ・ピコのmillisとmicros、なぜか遅い!? | トップページ | Arduino IDEでラズパイ・ピコ:Earle Philhower版で »

2022年4月 7日 (木)

Arduino IDEでラズパイ・ピコ:Serial出力がバッファされていないぞ

ラズパイ・ピコをArduino IDEで動かそうとしたけど
ということで、ゴソゴソしております。

なんやかんや分かってきたこと。

・タイマー割り込みについて

(1)「rp2040-datasheet.pdf」の「4.6.4.2. Set an alarm」
  に記されている方法を試したけど、受け付けてもらえ
  ませんでした。
https://github.com/raspberrypi/pico-examples/blob/master/timer/timer_lowlevel/timer_lowlevel.c#L25-L72

(2) Arduinoライブラリを探すと、
https://github.com/khoih-prog/MBED_RPI_PICO_TimerInterrupt
https://github.com/khoih-prog/RPI_PICO_TimerInterrupt
  の二つが出てきます。
Intr_lib1
  この「MBED_RPI_PICO_TimerInterrupt」を使うと
  定周期のタイマー割り込み(RP2040で言うところの
  アラーム割り込み)がうまくいきました。

1ms周期での割り込み例
Cc003_20220407115201
loopでパルスをon/offして割り込みが入った時の処理時間を
確かめました。

・シリアル出力・・・ちょっと問題
  こちらの環境では「Serial.print」がうまく
  行かなかったので「Serial1」を使っています。
   (端子GP0のUART0 TX)
この「Serial1.print」がバッファリングしていないのです。
1文字ずつの送出完了を待って文字列を出すのです。
115200ボーなら16文字で1.4ms。
電文の送出が終わるまで、他のことができません。
Arduino-UNOでさえ、送受とも64バイトのバッファを
持っていて割り込み処理してるのに・・・
  ※Serial1にしてるが悪いのかも?
   要調査案件。

Cc000_20220407115201

RP2040のUART、送受とも32文字のFIFOを持っている
はずなのですが、オシロ波形を見る限り生かされていない
ような感じです。

しかし・・・ 4月1日にテストした9600ボーでの出力は
ちゃんとバッファされているようだし・・・・
タイマー割り込みを使ったのが悪いの?
なんでしょね。

4月1日のスケッチをあらためて走らせてみたら・・・
送信データをバッファしなくなっていました。
  ※異なる波形がオシロに出ました。
4月1日以降、タイマー割り込みを動かすためにArduinoの環境を
あれこれしたので、どこかがおかしくなった可能性が大です。

ラズパイ・ピコ向けの環境、再構築でしょうかね。
困ったぞ!

・試したスケッチ。

/*****  ラズパイ・ピコ RP2040 1msタイマー割り込みのテスト  ****/ 
// TimerInterruptTest.ino
// For MBED RP2040-based boards such as Nano_RP2040_Connect, RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040.
// Written by Khoi Hoang
// Built by Khoi Hoang https://github.com/khoih-prog/MBED_RPI_PICO_TimerInterrupt
// Licensed under MIT license
// "This code is intended to run on the MBED RASPBERRY_PI_PICO platform!"
// "Please check your Tools->Board setting."
#include "MBED_RPi_Pico_TimerInterrupt.h"

/***** タイマーデータ *****/
volatile byte f_1ms; // 1msフラグ
volatile word tm_1ms; // 1msダウンカウントタイマー
volatile byte f_1sec; // 1秒フラグ
volatile word cnt_1000; // 1秒カウント
/***** シリアル出力 *****/
char tx_bff[64]; // sprintf用

/***** 1ms タイマー割り込み処理 *****/
void TimerHandler0(uint alarm_num)
{
//static byte f_x3 = 0; // GP3トグル用フラグ
TIMER_ISR_START(alarm_num); // ISR前処理
gpio_put(2, HIGH); // GP2 H 割り込み処理時間チェック
// gpio_put(3, f_x3); // GP3 トグル
// f_x3 ^= 1;
f_1ms = 1; // 1ms経過
if(tm_1ms) tm_1ms--; // 1msダウンカウントタイマー
cnt_1000++; // 1秒計時
if(cnt_1000 >= 1000){ // 1000 x 1ms
cnt_1000 = 0;
f_1sec = 1; // 1秒経過フラグをon
}
gpio_put(2, LOW); // GP2 L 割り込み処理時間チェック
TIMER_ISR_END(alarm_num); // ISR後処理
}

// Init MBED_RPI_PICO_Timer, can use any from 0-15 pseudo-hardware timers
MBED_RPI_PICO_Timer ITimer0(0);

/***** セットアップ *****/
void setup(){
pinMode(2, OUTPUT); // タイミングチェック用
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(25, OUTPUT); // LED
Serial1.begin(115200); // シリアル1で出力
ITimer0.attachInterruptInterval(1000, TimerHandler0); // タイマー0:1ms
}

/***** LOOP *****/
void loop(){
byte f_x5 = 0; // GP5トグル用
byte f_x25 = 0; // LEDトグル用
word cnt; // tm_1ms回数
uint32_t t; // micros経過時間
uint32_t us;
us = micros();
cnt = 0;
while(1){
gpio_put(5, f_x5); // GP5トグル
f_x5 ^=1; // loop時間チェック
// 時間経過チェック
if(f_1sec){ // 1秒経過?
f_1sec = 0;
gpio_put(25, f_x25); // LEDトグル
gpio_put(4, f_x25); // GP4も同時に
f_x25 ^=1;
}
if(tm_1ms == 0){ // 1msタイムアップ?
gpio_put(3, HIGH); // GP3 H
tm_1ms = 250; // 0.25秒をセット
t = micros() - us; // 経過時間(us)
us = micros();
sprintf(tx_bff, "%4d %4ld.%03ldms",
cnt, t / 1000, t % 1000);
gpio_put(3, LOW); // GP3 L
Serial1.println(tx_bff);
cnt++; // 回数
if(cnt > 9999) cnt = 0; // max9999
}
}
}


※その後
ボードマネージャーで一つ前のにしたら、バッファリングされる
ようになりました。
Bd300

こんな波形に。
Cd000

シリアルデータの出力が続いていても、
loopを回っているパルスが出ています。
この間は別の処理を動かせます。

しかし・・・
2発目の1ms割り込みでのタイミングのloopパルスを
見ると、割り込みで途切れているのが見えています。
Cd001
ところが・・・
シリアルデータを割り込みでバッファリングしていたら、
1ms割り込み以外の途切れも見えるはずです。
テストスッケッチでの送出文字数は17。
RP2040のFIFOは32文字。
文字数を多くしたらどうなるか、試してみます。
 :
 :

試しました。
32文字より増やしたら、その分だけ待ちが発生。
ということで、バッファリングは送信割り込みではなく
FIFOを使っているということになります。

しかし、ツールの環境を変えてダメになる場合が出る
とは・・・困った困った。




|

« ラズパイ・ピコのmillisとmicros、なぜか遅い!? | トップページ | Arduino IDEでラズパイ・ピコ:Earle Philhower版で »

ラズパイ・ピコ」カテゴリの記事

コメント

シリアル出力を割り込みなしで使うと・・・
デバッグなどのため、割り込み処理内でシリアル出力を行ってもOKに。
メイン側で行う出力と衝突しないようになります。

しかし、割り込み内で待ちのあるシリアル出力を行うのは危険。
115200ボーでも1文字を10bitとしたら87us。
12文字で1ms越え。
割り込み処理がどんどん遅くなります。

割り込みでシリアル出力してるスケッチ、けっこう見ますんで。
基本、割り込みはそのトリガー(イベント)を作るだけに。
時間のかかる処理は、メイン側で実行というのが、非力なマイコンを扱う定石です。

割り込み内でシリアル出力とか液晶表示など、言語道断・もってのほか。

投稿: 居酒屋ガレージ店主(JH3DBO) | 2022年4月 7日 (木) 16時54分

Arduno環境じゃなく、ラズパイの関数になるんですが
今回の「1msタイマー割り込み」で気になったのが、アラーム割り込みタイミングの設定方法です。
「void TimerHandler0(uint alarm_num)」を見ますと、前処理と後処理のルーチンが呼ばれています。
TIMER_ISR_START(alarm_num); // ISR前処理
TIMER_ISR_END(alarm_num); // ISR後処理

これ、何してるのと探しますと・・・
・前処理
void TIMER_ISR_START(uint alarm_num)
{
 absAlarmTime[alarm_num]._private_us_since_boot =
time_us_64() + _timerCount[alarm_num];
hardware_alarm_set_target(alarm_num, absAlarmTime[alarm_num]);
}

・タイマー割り込みの後処理:何もしていない

void TIMER_ISR_END(uint alarm_num)
{
}

問題は前処理の次のアラーム時間設定。
現在のタイマー値time_us_64()にインターバル時間を加算しているようです。
ということは、割り込み処理が遅れたら、次回の割り込みが遅れてしまいます。
速くなることはないので、どんどん遅れが積み重なることになるのかと。

定周期割り込みとして使うには、「ちょっとなぁ」です。

投稿: 居酒屋ガレージ店主(JH3DBO) | 2022年4月 8日 (金) 11時38分

コメントを書く



(ウェブ上には掲載しません)




« ラズパイ・ピコのmillisとmicros、なぜか遅い!? | トップページ | Arduino IDEでラズパイ・ピコ:Earle Philhower版で »