Arduino IDEでラズパイ・ピコ:1msタイマー割り込み
Arduino IDEでラズパイ・ピコ:Earle Philhower版
の導入で、Raspberry Pi Pico C/C++ SDKの関数がちゃんと
動き出したようです。
アラーム割り込みとPWM割り込みの二つで
1msタイマー割り込みを試してみました。
こんなスケッチ。
/***** 1msタイマー割り込みのテスト *****/
// タイマーとPWMで
// GP2 1msタイマー割込処理時間
// GP3 タイマー割込でトグル この周期が2.00598ms
// GP4 loopでトグル 割り込みでパルスが停止
// GP5 1kHz PWM出力
// GP6 PWM割込処理時間
// LED 1Hzで点滅
// millisによル送信データ間隔が1003ms
#include "hardware/pwm.h" // PWM処理に必要
#define nop() asm volatile ("nop\n\t") // nopコード
// ※参考
// https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__pwm.html
// https://github.com/raspberrypi/pico-examples/blob/master/pwm/led_fade/pwm_led_fade.c
// https://plaza.rakuten.co.jp/sorriman/diary/202103080000/
// データ
volatile word tm_1ms; // 1msダウンカウントタイマー
volatile byte f_1sec; // 1秒フラグ
word cnt_1sec; // 秒カウンタ
char tx_str[64]; // 送信文字列
/***** 1ms割り込み処理 *****/
struct repeating_timer st_tm1ms;
// 割り込み処理
bool tm1ms(struct repeating_timer *t)
{
static word cnt1000 = 0;
static byte f_x3 = 0;
gpio_put(2, HIGH); // GP2 H
f_x3 ^= 1;
gpio_put(3, f_x3); // GP3 トグル
if(tm_1ms) tm_1ms--;
cnt1000 ++;
if(cnt1000 >= 1000){
cnt1000 = 0;
f_1sec = 1;
}
gpio_put(2, LOW); // GP2 L
return true;
}
/***** 1kHz PWM割り込み *****/
word slice_num5; // GP5 PWMスライス番号
// 割り込み処理
void pwm1ms(void){
//static byte f_x6 = 0;
pwm_clear_irq(slice_num5);
gpio_put(6, HIGH); // GP6 H
nop(); nop(); nop(); nop(); // 時間待ち
nop(); nop(); nop(); nop();
gpio_put(6, LOW); // GP6 L
// gpio_put(6, f_x6); // GP6 トグル
// f_x6 ^=1;
}
/***** SETUP *****/
void setup() {
Serial1.begin(115200); // TX0
pinMode(2, OUTPUT); // GP2 1msタイマー割込時間
pinMode(3, OUTPUT); // GP3 1ms割り込みでトグル
pinMode(4, OUTPUT); // GP4 loopでトグル
pinMode(6, OUTPUT); // GP6 PWM割り込み
pinMode(25, OUTPUT); // LED
// GP5 PWM:1kHz 割り込み有効に
gpio_set_function(5, GPIO_FUNC_PWM); // GP5 PWMに
slice_num5 = pwm_gpio_to_slice_num(5); // PWMスライス番号
pwm_clear_irq(slice_num5);
pwm_set_irq_enabled(slice_num5, true);
irq_set_exclusive_handler(PWM_IRQ_WRAP, pwm1ms);
irq_set_enabled(PWM_IRQ_WRAP, true);
pwm_set_clkdiv(slice_num5, 100); // 1.25MHz
pwm_set_wrap(slice_num5, 1250-1); // 1kHz
pwm_set_chan_level(slice_num5, PWM_CHAN_B, 625); // duty50%
pwm_set_enabled(slice_num5, true); // PWMスタート
// 1msサイクルでタイマー割り込み
add_repeating_timer_us(1000, tm1ms, NULL, &st_tm1ms);
}
/***** LOOP *****/
void loop() {
byte f_x4 = 0;
byte f_x25 = 0;
uint32_t ms, t;
ms = millis();
while(1){
if(f_1sec){ // 1秒ごとにシリアル出力
f_1sec = 0;
cnt_1sec++;
if(cnt_1sec > 9999) cnt_1sec = 0;
t = millis() - ms;
ms = millis();
sprintf(tx_str, "%4dsec %4ldms",
cnt_1sec, t);
Serial1.println(tx_str);
}
f_x4 ^= 1; // loopでトグル
gpio_put(4, f_x4); // GP4 トグル
if(tm_1ms == 0){ // 0.5秒経過
tm_1ms = 500;
f_x25 ^= 1;
gpio_put(25, f_x25); // LED トグル
}
}
}
・シリアル出力はTX0に。
・実行の様子はポートにパルスとして出力。
・GP2とGP3がアラーム割り込みによるパルス。
GP3が500Hzでトグルします。
・GP4は処理loopでトグルパルスを出力。
割り込みなどが入ると、このパルスが止まります。
・GP5が1kHzのPWM出力。
50%デューテューに設定。
・GP6がPWM割り込みの処理時間。
問題なのがアラーム割り込み。
2022年4月8日にコメントしましたが、アラーム割り込み
を使うとこの中での処理遅れが加算されるのです。
※一定周期の時間が欲しい時はアウトです。
間違いなく一定周期が得られるPWMと比べて、どのくらい
違うかというと・・・
アラーム割り込み(500Hzでトグル)が
周期 2.005983ms
1KHzのPWM出力が
周期 0.9999975ms
1kHzに換算すると「1.00299倍」。
millisで間隔「1003ms」と出てくるので、
方形波パルスの周波数は正しいようです。
やはりアラーム割り込みによる繰り返しはダメ。
1msアラーム割り込みの処理時間はこんなのです。
GP2をH/Lしている割り込み処理の区間は約0.3us。
しかし、loopパルスが途絶えている区間が8usほど
になっています。
これが実際の割り込み処理時間になるわけです。
毎回の1ms割り込みで「3us」が積み重なると、
1秒で3msの遅れとなり、だいたいのつじつまが
合ってきます。
※重要
・一定周期の発生にはアラーム割り込みは適さない。
・利用できるのはPWM割り込み。
・PWM __↑ ̄ パルスエッジの直前で割り込みがかかる。
・PWM割り込み、実質的に一つしか使えない。
どのPWMチャンネルから割り込みが入ったの
チェックがむつかしいかと。
| 固定リンク
「ラズパイ・ピコ」カテゴリの記事
- トラ技2024年5月号に「3.3/65535」(2024.04.07)
- ラズピコだと1/65535が出現(2024.03.30)
- Help me! ラズピコ、Philhower版だとスケッチをアップロードできない(2023.04.12)
- Arduino IDEでのラズピコ開発環境 Philhower版が正解でしょう(2023.04.04)
- ラズピコのピン:自由になりそうだけど定義で固定されている(2023.04.03)
「割り込み処理」カテゴリの記事
- 1クロックでも速くしたい 割込を「ISR_NAKED」で(2024.09.30)
- 1クロックでも速くしたい DDS方式の2相パルス発生器(2024.09.27)
- 最適化処理のせいで悩んだぞ 呪文volatile再び(2024.06.06)
- I2C液晶のアクセス、割り込みで処理しないようにすると(2024.04.12)
- I2C液晶のアクセス、割り込み処理で遅れる原因らしきもの(2024.04.07)
コメント
PICO-SDKのタイマー割込みセットで、
add_repeating_timer_us(-1, my_isr, NULL, interval_us); があります、
この-1が曲者で、-1(負の値)の時は、割り込みの先頭でタイマーの初期化・割り込み待ちになります、1(正の値)にすると割り込みの最後で割り込みの初期化割り込み待ちになるということで、割り込み処理だけ遅れます。
アラームは1になっているのだろうと思います。C++の時はこれで結構正しい1msが出力されていましたが・・・・・
投稿: | 2024年1月17日 (水) 14時38分
ここしばらく、ピコで遊んでいません。
・・・使わないとすぐに忘れてしまいます。
投稿: 居酒屋ガレージ店主(JH3DBO) | 2024年1月18日 (木) 10時41分