« Arduino IDEでラズパイ・ピコ:Earle Philhower版で | トップページ | Arduino IDEでRaspberry Pi Pico:Win7でのUSB問題解決です »

2022年4月12日 (火)

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アラーム割り込みの処理時間はこんなのです。
Aa1_20220412142701
GP2をH/Lしている割り込み処理の区間は約0.3us。
しかし、loopパルスが途絶えている区間が8usほど
になっています。
これが実際の割り込み処理時間になるわけです。
毎回の1ms割り込みで「3us」が積み重なると、
1秒で3msの遅れとなり、だいたいのつじつまが
合ってきます。

※重要
・一定周期の発生にはアラーム割り込みは適さない。
・利用できるのはPWM割り込み。
・PWM __↑ ̄ パルスエッジの直前で割り込みがかかる。
・PWM割り込み、実質的に一つしか使えない。
    どのPWMチャンネルから割り込みが入ったの
    チェックがむつかしいかと。


|

« Arduino IDEでラズパイ・ピコ:Earle Philhower版で | トップページ | Arduino IDEでRaspberry Pi Pico:Win7でのUSB問題解決です »

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

コメント

コメントを書く



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




« Arduino IDEでラズパイ・ピコ:Earle Philhower版で | トップページ | Arduino IDEでRaspberry Pi Pico:Win7でのUSB問題解決です »