; CLOCK = 2MHz

.program tm1637out
.side_set 1 opt

.wrap_target            ; Start Condition
    pull block
    set pindirs,0b00    ; SDA/SCL input
    nop     [7]         ; 8 Clocks
    set pindirs,0b01    ; SDA output/SCL input
    set pins,0          ; SDA is Low
    nop     [7]         ; 8 Clocks
    set pindirs,0b11    ; SDA/SCL output
    set x,7 side 0      ; CLK is Low
    jmp output

; 1バイト出力
byte_loop:
    set x, 7 side 0     ; Clock Low
    pull block
output:
    nop     [3]         ; 4 Clock
    out pins,1  [4]     ; LSB output
    nop     side 1      ; CLK is High
    nop     [7]         ; 8 clocks
    nop     side 0      ; CLK is Low
    jmp x-- output      ;

; ACK判定
    set pindirs,0b10  [7]  ; SDA input/SCL output
    nop     side 1      ; SCL = High
    jmp pin nack        ; if SDA == 0 then ACK
    jmp ack

nack:
    irq 0 rel          ; NACK

; Stop判定
ack:
    nop     [6]
    nop     side 0          ; CLK is Low (ACK cycle end)
    set pindirs, 0b11  [7]  ; SDA/SCL Output (next byte or stop)
    out x, 1                ; 9bit目
    jmp !x byte_loop        ; 0ならStopせずにループ

; Stop Condition
stop:
    set pins, 0     [7]     ; SDA is Low
    nop     side 1          ; SCL is High
    nop     [7]
    set pindirs, 0b00       ; SDA/SCL Input (pull-up makes it High) -> STOP
    nop     [7]
.wrap


% c-sdk {

#include "hardware/clocks.h"

#define SM_CLOCK    2000000.0

void tm1637out_program_init(PIO pio, uint sm, uint offset, uint sda, uint clk) {

   // pull up
   gpio_pull_up(sda);
   gpio_pull_up(clk);    

   // SDA & CLK
   pio_gpio_init(pio, sda);
   pio_gpio_init(pio, clk);
   pio_sm_set_consecutive_pindirs(pio, sm, clk, 1, false);  // 初期状態はInput
   pio_sm_set_consecutive_pindirs(pio, sm, sda, 1, false);  // 同上

   pio_sm_config c = tm1637out_program_get_default_config(offset);

   // out = set = jmp = SDA
   sm_config_set_out_pin_base(&c, sda);
   sm_config_set_out_pin_count(&c, 1);
   sm_config_set_set_pin_base(&c, sda);
   sm_config_set_set_pin_count(&c, 2);
   sm_config_set_jmp_pin(&c, sda);

   // sideset = clk
   sm_config_set_sideset_pin_base(&c, clk);

   // out = Right shift
   sm_config_set_out_shift(&c, true, false, 0);

   // SM Clock = 2MHz
   float clkdiv = (float)clock_get_hz(clk_sys) / SM_CLOCK;
   sm_config_set_clkdiv(&c, clkdiv);

   // TX FIFO join
   sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
   
   pio_sm_init(pio, sm, offset, &c);
}
%}
