SNSへはこちら

Longan NanoでRISC-Vチャレンジ(7) - ADC/DAC

続いてアナログ関連のペリフェラル設定をしていきましょう。

ADC

制御器としてマイコンを使う上で必須の機能です。このマイコンの型番は GD32VF103 ですが、STM32F103 と似たような機能です。STM32F303 を使っている人はコンバート開始の方法に戸惑うかも。

取り敢えずコードです。1つのチャネルを変換するという動作の実装です。 adc_init ではチャネル0を想定して初期化をしてしまいました。

void adc_init(void) {
    rcu_periph_clock_enable(RCU_GPIOA);
    gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_0);

    RCU_CFG0 |= (0b10 << 14) | (1 << 28); // ADC clock = 108MHz / 8 = 13.5MHz(14MHz max.)
    rcu_periph_clock_enable(RCU_ADC0);
    ADC_CTL1(ADC0) |= ADC_CTL1_ADCON;
}

uint16_t get_adc(int ch) {
    ADC_RSQ2(ADC0) = 0;
    ADC_RSQ2(ADC0) = ch;
    ADC_CTL1(ADC0) |= ADC_CTL1_ADCON;

    while( !(ADC_STAT(ADC0) & ADC_STAT_EOC) );

    uint16_t ret = ADC_RDATA(ADC0) & 0xFFFF;
    ADC_STAT(ADC0) &= ~ADC_STAT_EOC;
    return ret;
}

STM32F303 では ADSTART というビットがレジスタに用意されているのですが、F103 ではADON を立てて ADC 自体を有効化した状態で、チャネルを設定した後に更にもう一度 ADON に対して1を代入しなければならないという仕様です。このマイコンは後者の仕様を受け継いでいるため、初期化と A/D 値を get するのに両方の操作が必要になるということに注意です。

DAC

実はメチャクチャ簡単。DAC です。
GPIO の CTLx レジスタを見ると「アナログの出力設定が無いじゃないか」と思われるかも知れませんが、実は DAC を有効化すると、指定したチャネルのピンが自動的にアナログ出力になるという、昔の 8bit マイコンを彷彿とさせる仕様なのです。これは STM32F303 と共通の仕様です。

void dac_init(void) {
    rcu_periph_clock_enable(RCU_DAC);
    rcu_periph_clock_enable(RCU_GPIOA);
    // No need for pin setting because the function is automatically enabled when DACx is enabled.
    DAC_CTL = DAC_CTL_DEN0;
}

void dac_write(int i) {
    DAC0_R12DH = i;
}

ちなみにこうするとLEDボヤァができます。でもまあLEDの電圧-電流特性が線形ではないので少し微妙ですがね。

while(1) {
    for(int i = 0; i < (1 << 12); i++) {
        dac_write(i++);
    }
}