#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/dma.h"
#include "hardware/pwm.h"
#include "hardware/clocks.h"

#define AUDIO_OUT_PIN   2

__asm(\
  ".section \".rodata\" \n"
  ".balign 4\n"

  ".global _audio_data\n"
  ".global _audio_data_len\n"

  "_audio_data:\n"
  ".incbin \"test12.raw\"\n"
  ".set _audio_data_len, . - _audio_data\n"
  ".section \".text\"\n"
);

extern const uint8_t _audio_data[];
extern uint32_t _audio_data_len[];

uint slice_num = 0;
int dma_ch = 0;

int main()
{
    stdio_init_all();

    printf("audio_data_len = %d\n", _audio_data_len);

    // サンプリング周波数の都合でシステムクロックを
    // 125MHzに切り替える
    set_sys_clock_khz(125000, true);

    // PWM出力ピン
    gpio_set_function(AUDIO_OUT_PIN, GPIO_FUNC_PWM);
    // スライス番号
    slice_num = pwm_gpio_to_slice_num(AUDIO_OUT_PIN);

    // PWMの設定
    pwm_config pwm_conf = pwm_get_default_config();
    pwm_config_set_wrap(&pwm_conf, 4095);   // PWM周波数15.259kHz
    pwm_config_set_clkdiv(&pwm_conf, 2.0f); // 62.5MHz
    pwm_init(slice_num, &pwm_conf, false);

    // DMAの設定
    dma_ch = dma_claim_unused_channel(true);
    dma_channel_config dma_conf = dma_channel_get_default_config(dma_ch);
    // 粒度は16bit中の下位12bit
    channel_config_set_transfer_data_size(&dma_conf, DMA_SIZE_16);
    // 送り出しはメモリ
    channel_config_set_read_increment(&dma_conf, true);
    // 受け側はDMAのCCレジスタ
    channel_config_set_write_increment(&dma_conf, false);
    // DREQを設定
    channel_config_set_dreq(&dma_conf, pwm_get_dreq(slice_num));
    // DMAチャネル設定
    dma_channel_configure(
        dma_ch,
        &dma_conf,
        (uint16_t *)&pwm_hw->slice[slice_num].cc+2, // 書き込み先はCCレジスタ
        (uint8_t *)_audio_data,             // 読み出し元は12bitオーディオデータ
        (uint)_audio_data_len,               // 転送回数
        false                         // 開始しない
    );
    // PWMを開始
    pwm_set_enabled(slice_num, true);
    // DMA転送を開始
    dma_channel_start(dma_ch);

    // DMAが完了するのを待つ
    dma_channel_wait_for_finish_blocking(dma_ch);
    // 再生終了
    pwm_set_enabled(slice_num, false);

    while (true) {
        tight_loop_contents();
    }
}
