; DHT11を駆動するPIOコード

.program dht11

.wrap_target
    ; ウェイト用の値として20000をメインプログラムから受け取る
    pull block      ; osr = 20000

    set pindirs, 1  ; Set pinsを出力に切り替え
; スタートパルス20ms以上
    set pins, 0     ; Low
    mov x,osr       ; 20 000 us
start_pulse:
    jmp x-- start_pulse

    set pindirs, 0  ; 入力に切り替え

;   スタートパルスを待つ
    mov  isr,null  ; ISRを0クリア
    wait 1 pin, 0  ; バスがHighかチェック
    wait 0 pin, 0  ; LOWを待つ
    wait 1 pin, 0  ; HIGHを待つ

    set y, 4       ; 5バイトを読み取る

; 1バイト読み取りスタート
start_byte:
    mov osr, y      ; OSRにバイト数を退避
    set y, 7        ; 8bitを読み取る
bit_start:
    wait 0 pin, 0   ; LOWになるまで待つ
    wait 1 pin, 0   ; パルス
    set x, 29       ; 30us以上HIGHなら1
pulse_width_count:
    jmp x-- pulse_width_count
    in pins, 1      ; ISRにピンの値を入力し1bit終了
    jmp y-- bit_start

    ; 8bit読み取り終了
    push noblock   ; ISRをFIFOにプッシュ
    irq set 0       ; 割り込み発生
    mov y, osr      ; バイト数カウンタを復帰
    jmp y-- start_byte
; 5バイト読み取り完了
    irq set 1
.wrap

% c-sdk {
#include "hardware/clocks.h"

void dht11_program_init(PIO pio, uint sm, uint offset, uint pin) {
    gpio_disable_pulls(pin);    // pinのプルアップダウンを無効化しておく
    pio_gpio_init(pio, pin);
    
    pio_sm_config c = dht11_program_get_default_config(offset);
    // Set pins
    sm_config_set_set_pins(&c, pin, 1);

    // In pins
    sm_config_set_in_pin_base(&c, pin);
    sm_config_set_in_pin_count(&c, 1);
    sm_config_set_in_shift(&c, false, false, 0);

    // 1MHz動作に
    float clkdiv = (float)clock_get_hz(clk_sys) / 1000000;
    sm_config_set_clkdiv(&c, clkdiv);

    pio_sm_init(pio, sm, offset, &c);
}
%}
