STM32F446 の内蔵 ADC, DAC 用のライブラリ.このライブラリを登録した際のプログラム: Demo_DSP_ADDA. Library for build-in ADC and DAC in STM32F446.

Dependents:   Demo_DSP_ADDA F446_DSP_FFT_Analyzer TrG_FFT_Analyzer DSP_MultirateLinearphase ... more

DSP_AdcBase.cpp

Committer:
MikamiUitOpen
Date:
2020-12-20
Revision:
3:a1dcee67c67e
Parent:
2:7d58c617d76a

File content as of revision 3:a1dcee67c67e:

//-------------------------------------------------------------
//  STM32F446 内蔵 ADC のための抽象基底クラス
//
//  2020/12/20, Copyright (c) 2020 MIKAMI, Naoki
//-------------------------------------------------------------

#include "DSP_AdcBase.hpp"
#pragma diag_suppress 870   // マルチバイト文字使用の警告抑制のため

namespace Mikami
{
    // コンストラクタ
    DspAdcBase::DspAdcBase(float fSampling, PinName pin,
                             ADC_TypeDef* const adc)
    {
        // このクラスのオブジェクトの複数生成禁止のため
        MBED_ASSERT(!created_);
        created_ = true;

        // pin に対応する ADC が存在するか確認
        MBED_ASSERT(PinmapMatch(pin, adc));
        
        // 引数で指定された AD 変換器を使うように設定
        myAdc_ = adc;

        // pin に対応する GPIOx_MODER をアナログ・モードに設定する
        pin_function(pin, STM_MODE_ANALOG);
        // pin_function() が定義されている pinmap.c が含まれるディレクトリ:
        // mbed-dev\targets\TARGET_STM

        // ADC にクロックを供給する
        // クロック供給用マクロの定義:stm32f4xx_hal_rcc_ex.h
        switch ((uint32_t)adc)
        {
            case ADC_1 : __HAL_RCC_ADC1_CLK_ENABLE(); break;
            case ADC_2 : __HAL_RCC_ADC2_CLK_ENABLE(); break;
            case ADC_3 : __HAL_RCC_ADC3_CLK_ENABLE(); break;
        }

        // 1 チャンネルのみ使用の設定
        myAdc_->SQR1 &= ~ADC_SQR1_L;

        // pin に対応するチャンネルを使うための設定
        myAdc_->SQR3 = STM_PIN_CHANNEL(pinmap_function(pin, PinMap_ADC));
        // pinmap_function() のヘッダファイル: mbed\hal\pinmap.h
        // pinmap_function() が定義されているファイル: mbed-dev\hal\mbed_pinmap_common.c
        // STM_PIN_CHANNEL() の定義:mbed\TARGET_NUCLEO_F446RE\TOOLCHAIN_ARM_STD\
        //                           PinNamesTypes.h

        // ADC の CR1 の設定
        myAdc_->CR1 = 0x0;  // 12bit, 非Scan モード,AD 変換終了割込みを禁止

        // ADC の CR2 の設定
        myAdc_->CR2 = ADC_EXTERNALTRIGCONVEDGE_RISING   // 外部トリガの立ち上がりで開始される
                    | ADC_EXTERNALTRIGCONV_T8_TRGO      // 外部トリガ: Timer8 TRGO event
                    | ADC_CR2_ADON;                     // ADC を有効にする

        // AD 変換器の外部トリガに使うタイマ (TIM8) の設定
        SetFs(fSampling);
    }

    // AD 変換器の外部トリガに使うタイマ (TIM8) の設定
    //      fSampling   標本化周波数 [kHz]
    void DspAdcBase::SetFs(float fSampling)
    {
        __HAL_RCC_TIM8_CLK_ENABLE();    // クロック供給. "stm32f4xx_hal_rcc.h" 参照
        TIM_TypeDef* const TIM = TIM8;

        TIM->CR2 = TIM_TRGO_UPDATE;     // Update event を TRGO とする

        uint32_t psc = 0;
        uint16_t mul = 1;
        fSampling = fSampling*1000;     // Hz 単位に変換
        uint32_t arr;
        while (true)
        {
            arr = (uint32_t)(SystemCoreClock/(mul*fSampling) + 0.5f);
            if (arr <= 65536) break;
            psc++;
            mul++;
            MBED_ASSERT(psc <= 65536);  // 標本化周波数が低すぎないかチェック
        }
        TIM->ARR = arr - 1;     // Auto-reload レジスタの設定
        TIM->PSC = psc;         // Prescaler の設定
        TIM->CR1 = TIM_CR1_CEN; // TIM8 を有効にする
    }

    //  pin に対応する AD 変換器が存在することを確認する
    //      pin     A0, PA_0 など
    //      adc     ADC1 など
    bool DspAdcBase::PinmapMatch(PinName pin, ADC_TypeDef* const adc)
    {
        for (int n=0; PinMap_ADC[n].pin != NC; n++)
            if ( ((PinMap_ADC[n].pin & 0xFF) == pin) &
                 (PinMap_ADC[n].peripheral == (uint32_t)adc) ) return true;
        return false;
    }

    // static メンバの実体
    ADC_TypeDef* DspAdcBase::myAdc_;
    bool DspAdcBase::created_ = false;
}