パルス検出をCPUによるポーリング手法で行なうと、240nsec以下のパルス幅では取りこぼしが発生した。そこで、GPIOの割込みを利用した2つのパルス検出手法で検討を進める。

1系統GPIOでLOWエッジとHIGHエッジの両方を検出する手法と、2系統GPIOでLOWエッジとHIGHエッジをそれぞれ検出する手法である。共通の割込みハンドラー、1系統制御関数、2系統制御関数を以下に示す。

なお、3つのパルス入力ピンは、ラズピコ実装のブレッドボード上で接続されている。

#define PICO_PULSE_OUT_PIN     1 // パルス出力ピン
#define PICO_PULSE_IN_PIN      2 // パルス入力ピン
#define PICO_PULSE_IRQ1_PIN    4 // パルス入力ピン(GPIO割込み1)
#define PICO_PULSE_IRQ2_PIN    5 // パルス入力ピン(GPIO割込み2)
#define PICO_PULSE_DETECT_PIN 15 // パルス検出ピン

#define HIGH 1
#define LOW  0

bool loEdgeFlag = false; // LOWエッジ検出フラグ
bool hiEdgeFlag = false; // HIGHエッジ検出フラグ

// GPIOエッジ割込みハンドラー
void gpio_callback(uint gpio, uint32_t events) {
    // 1系統GPIO
    if (gpio == PICO_PULSE_IN_PIN && events == GPIO_IRQ_EDGE_FALL) {
        loEdgeFlag = true; // LOWエッジ検出
    }
    else if (gpio == PICO_PULSE_IN_PIN && events == GPIO_IRQ_EDGE_RISE) {
        hiEdgeFlag = true; // HIGHエッジ検出
    }
    // 2系統GPIO
    else if (gpio == PICO_PULSE_IRQ1_PIN && events == GPIO_IRQ_EDGE_FALL) {
        loEdgeFlag = true; // LOWエッジ検出
    }
    else if (gpio == PICO_PULSE_IRQ2_PIN && events == GPIO_IRQ_EDGE_RISE) {
        hiEdgeFlag = true; // HIGHエッジ検出
    }
}

// 1系統GPIO割込み動作開始・停止
void control_GPIOIRQ_1(bool state) {
    // LOWエッジとHIGHエッジ設定
    gpio_set_irq_enabled_with_callback(PICO_PULSE_IN_PIN, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, 
        state, &gpio_callback);
}

// 2系統GPIO割込み動作開始・停止
void control_GPIOIRQ_2(bool state) {
    // LOWエッジ設定
    gpio_set_irq_enabled_with_callback(PICO_PULSE_IRQ1_PIN, GPIO_IRQ_EDGE_FALL,
        state, &gpio_callback);
    // HIGHエッジ設定
    gpio_set_irq_enabled_with_callback(PICO_PULSE_IRQ2_PIN, GPIO_IRQ_EDGE_RISE,
        state, &gpio_callback); 
}

以下は、1系統GPIO割込みによるパルス検出のコア部分。タイマー割り込みなどに関する部分は、前項「ポーリング手法」を参考にして欲しい。

パルス幅を1024nsecから16nsec単位で減少させていく。最初は1秒間の周期1msecのパルス数1,000を維持しているがが、576nsecから取りこぼしが発生し、512nsecで割込みが停止する。1つのGPIOにLOWエッジとHIGHエッジのコールバックを設定した場合は、一定間隔以上のパルス幅でないと内部処理が間に合わないようだ。従って、「一瞬の変化を捉える」という目的には、1系統GPIO割込みは使えないことが判明した。

uint32_t detect_number = 0; // 1秒間のパルス検出回数
control_GPIOIRQ_1(true);    // 1系統GPIO割込み動作開始

while (true) {
    if (loEdgeFlag && hiEdgeFlag) { // パルス検出
        gpio_put(PICO_PULSE_DETECT_PIN, HIGH); // パルス検出ピンHIGH
        detect_number++; // パルス検出数インクリメント
        if (oneSecFlag) { // 1秒経過
            gpio_put(PICO_PULSE_DETECT_PIN, HIGH); // パルス検出ピンHIGH
            multicore_fifo_push_blocking((uint32_t)detect_number); // 表示更新(実測150nsec)
            detect_number = 0; // パルス検出数クリア
            oneSecFlag = false; // 1秒経過フラグクリア
            update_PWM(PICO_PULSE_OUT_PIN); // パルス幅更新(1024nsecから16nsec循環)
         }
         sleep_us(1); // 1usec休止(オシロスコープ確認用)
         gpio_put(PICO_PULSE_DETECT_PIN, LOW); // パルス検出ピンLOW
         loEdgeFlag = false; // LOWエッジ検出フラグクリア
         hiEdgeFlag = false; // HIGHエッジ検出フラグクリア
    }
    // パルス幅512nsec以下の割込み発生停止に対する例外処理
    else if (oneSecFlag) {
        multicore_fifo_push_blocking((uint32_t)detect_number);
        detect_number = 0;
        oneSecFlag = false;
        update_PWM(PICO_PULSE_OUT_PIN);
    }
}

576nsecから取りこぼし発生、512nsecで割込み停止

以下は、2系統GPIO割込みによるパルス検出のコア部分。実験結果から、パルス幅が最小の16nsecになっても、パルス検出数1,000を維持できた。2系統GPIO割込みは有用であることが判明したが、1つの信号に対して、2つのGPIOを割り当てるというデメリットがある。

uint32_t detect_number = 0; // 1秒間のパルス検出回数
control_GPIOIRQ_2(true);    // 2系統GPIO割込み動作開始

while (true) {
    if (loEdgeFlag) { // LOWエッジ検出
        gpio_put(PICO_PULSE_DETECT_PIN, HIGH); // パルス検出ピンHIGH
        if (hiEdgeFlag) { // HIGHエッジ検出
            detect_number++; // パルス検出数インクリメント
            if (oneSecFlag) { // 1秒経過
                multicore_fifo_push_blocking((uint32_t)detect_number); // 表示更新(実測150nsec)
                detect_number = 0; // パルス検出数クリア
                oneSecFlag = false; // 1秒経過フラグクリア
                update_PWM(PICO_PULSE_OUT_PIN); // パルス幅更新(1024nsecから16nsec循環)
             }
             sleep_us(1); // 1usec休止(オシロスコープ確認用)
             gpio_put(PICO_PULSE_DETECT_PIN, LOW); // パルス検出ピンLOW
             loEdgeFlag = false; // LOWエッジ検出フラグクリア
             hiEdgeFlag = false; // HIGHエッジ検出フラグクリア
        }
    }
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です