
CQ出版社セミナ,2021/12/07開催「実習・C++言語によるArmマイコンのプログラミング」で使うプログラム.
Dependencies: Array_Matrix mbed SerialTxRxIntr UIT_FFT_Real
Revision 2:d28a3f741217, committed 2020-01-28
- Comitter:
- MikamiUitOpen
- Date:
- Tue Jan 28 01:27:07 2020 +0000
- Parent:
- 1:a90b573b335a
- Child:
- 3:687ae0dd092f
- Commit message:
- 3
Changed in this revision
--- a/ADDA_BasePolling/F446_ADC_Intr.cpp Fri Jan 17 02:04:09 2020 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -//------------------------------------------------------------- -// F446 内蔵 ADC2 を割込み方式で使うための派生クラス -// 基底クラス: AdcF446_Polling -// -// 2020/01/12, Copyright (c) 2020 MIKAMI, Naoki -//------------------------------------------------------------- - -#include "F446_ADC_Intr.hpp" - -namespace Mikami -{ - // 割込みベクタの設定と AD 変換割込みを有効にする - void AdcF446_Intr::SetIntrVec(void (*Func)()) - { - fp = Func; // 引数として渡された処理を割り当てる - NVIC_SetVector(ADC_IRQn, (uint32_t)Isr); // "core_cm4.h" 参照 - NVIC_EnableIRQ(ADC_IRQn); // "core_cm4.h" 参照 - } - - // static メンバの実体 - void (*AdcF446_Intr::fp)(); -}
--- a/ADDA_BasePolling/F446_ADC_Intr.hpp Fri Jan 17 02:04:09 2020 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -//------------------------------------------------------------- -// F446 内蔵 ADC2 を割込み方式で使うための派生クラス(ヘッダ) -// 基底クラス: AdcF446_Polling -// -// 2020/01/12, Copyright (c) 2020 MIKAMI, Naoki -//------------------------------------------------------------- - -#include "F446_ADC_Polling.hpp" - -#ifndef ADC_F446_INTERRUPT_HPP -#define ADC_F446_INTERRUPT_HPP - -namespace Mikami -{ - class AdcF446_Intr : public AdcF446_Polling - { - public: - // コンストラクタ - // fSampling 標本化周波数 [kHz] - // pin 入力ピンの名前 - AdcF446_Intr(float fSampling, PinName pin) - : AdcF446_Polling(fSampling, pin) - { myAdc_->CR1 |= ADC_CR1_EOCIE; } // AD 変換終了割り込みを許可 - - virtual ~AdcF446_Intr() {} - - // 割込みベクタの設定と AD 変換割込みを有効にする - void SetIntrVec(void (*Func)()); - - // AD 変換された値を読み込む - // -1.0f <= AD変換された値 < 1.0f - virtual float Read() const { return ToFloat(myAdc_->DR); } - - private: - static void (*fp)(); // 割込みサービス・ルーチンの中で実行される関数のポインタ - - // 割込みサービス・ルーチン,このクラスで使っている ADC であることを確認 - static void Isr() - { if ((myAdc_->SR & ADC_SR_EOC_Msk) == ADC_SR_EOC) fp(); } - }; -} -#endif // ADC_F446_INTERRUPT_HPP
--- a/ADDA_BasePolling/F446_ADC_Polling.cpp Fri Jan 17 02:04:09 2020 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -//------------------------------------------------------------- -// F446 内蔵 ADC2 のためのポーリング方式のクラス -// -// 2020/01/12, Copyright (c) 2020 MIKAMI, Naoki -//------------------------------------------------------------- - -#include "F446_ADC_Polling.hpp" -#include "PeripheralPins.h" // PinMap_ADC を使う場合に必要 -#pragma diag_suppress 870 // マルチバイト文字使用の警告抑制のため -// PeripheralPins.c は以下よりたどって行けば取得可能 -// https://gitlab.exmachina.fr/fw-libs/mbed-os/tree/5.8.1 - -namespace Mikami -{ - // コンストラクタ - AdcF446_Polling::AdcF446_Polling(float fSampling, PinName pin) - { - SetGPIO(pin); // GPIO の設定 - - __HAL_RCC_ADC2_CLK_ENABLE(); // ADC2 にクロックを供給する - // __HAL_RCC_ADC2_CLK_ENABLE() の定義:stm32f4xx_hal_rcc_ex.h - - // pin に対応するチャンネルを使うための設定 - myAdc_->SQR3 = STM_PIN_CHANNEL(pinmap_function(pin, PinMap_ADC)); - // pinmap_function() のヘッダファイル: mbed\hal\pinmap.h - // STM_PIN_CHANNEL() の定義:PinNamesTypes.h - - // ADC の CR1 の設定 - myAdc_->CR1 = 0x0; // AD 変換終了割り込みを禁止 - // ADC の CR2 の設定 - myAdc_->CR2 = ADC_EXTERNALTRIGCONVEDGE_RISING // 外部トリガの立ち上がりで開始される - | ADC_EXTERNALTRIGCONV_T8_TRGO // 外部トリガ: Timer8 TRGO event - | ADC_CR2_ADON; // ADC を有効にする - - // AD 変換器の外部トリガに使うタイマ (TIM8) の設定 - SetTim8(fSampling); - } - - // AD 変換器の外部トリガに使うタイマ (TIM8) の設定 - // fSampling 標本化周波数 [kHz] - void AdcF446_Polling::SetTim8(float fSampling) - { - __HAL_RCC_TIM8_CLK_ENABLE(); // クロック供給. "stm32f4xx_hal_rcc.h" 参照 - TIM_TypeDef* const TIM = TIM8; - - TIM->CR2 = TIM_TRGO_UPDATE; // Update event を TRGO (trigger output) とする - - float arrF = (SystemCoreClock/fSampling)/1000.0f; - if (arrF >65535) - { - fprintf(stderr, "%8.2f kHz : 標本化周波数が低すぎます.\r\n", fSampling); - while (true) {} - } - TIM->ARR = floor(arrF + 0.5f) - 1; // Auto-reload レジスタの設定 - TIM->PSC = 0; // Prescaler の設定 - TIM->CR1 = TIM_CR1_CEN; // TIM8 を有効にする - } - - // AD 変換器に関係のある GPIO の設定 - void AdcF446_Polling::SetGPIO(PinName pin) - { - // 各シンボルは stm32f4xx_hal_gpio.h で定義されている - // MODIFY_REG() マクロは stm32f4xx.h で定義されている - uint32_t nShift = STM_PIN(pin) << 1; - uint32_t moder = GPIO_MODE_ANALOG << nShift; - uint32_t mask = 0x03 << nShift; - switch (STM_PORT(pin)) - { - case 0: - if (__HAL_RCC_GPIOA_IS_CLK_DISABLED()) - __HAL_RCC_GPIOA_CLK_ENABLE(); // GPIOA にクロックを供給 - MODIFY_REG(GPIOA->MODER, mask, moder); // GPIOA のピンを設定 - break; - case 1: - if (__HAL_RCC_GPIOB_IS_CLK_DISABLED()) - __HAL_RCC_GPIOB_CLK_ENABLE(); // GPIOB にクロックを供給 - MODIFY_REG(GPIOB->MODER, mask, moder); // GPIOB のピンを設定 - break; - case 2: - if (__HAL_RCC_GPIOC_IS_CLK_DISABLED()) - __HAL_RCC_GPIOC_CLK_ENABLE(); // GPIOC にクロックを供給 - MODIFY_REG(GPIOC->MODER, mask, moder); // GPIOC のピンを設定 - break; - } - } - - // static メンバの実体 - ADC_TypeDef* const AdcF446_Polling::myAdc_ = ADC2; -}
--- a/ADDA_BasePolling/F446_ADC_Polling.hpp Fri Jan 17 02:04:09 2020 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -//------------------------------------------------------------- -// F446 内蔵 ADC2 のためのポーリング方式のクラス(ヘッダ) -// -// 2020/01/12, Copyright (c) 2020 MIKAMI, Naoki -//------------------------------------------------------------- - -#include "mbed.h" - -#ifndef ADC_F446_POLLING_HPP -#define ADC_F446_POLLING_HPP - -namespace Mikami -{ - class AdcF446_Polling - { - public: - // コンストラクタ - // fSampling 標本化周波数 [kHz] - // pin 入力ピンの名前 - AdcF446_Polling(float fSampling, PinName pin); - - virtual ~AdcF446_Polling() {} - - // AD 変換された値を読み込む - // -1.0f <= AD変換された値 < 1.0f - virtual float Read() const - { - while ((myAdc_->SR & ADC_SR_EOC) != ADC_SR_EOC) {} - return ToFloat(myAdc_->DR); - } - - protected: -//// ADC_TypeDef* const myAdc_; // AD 変換器に対応するポインタ - static ADC_TypeDef* const myAdc_; // AD 変換器に対応するポインタ - - float ToFloat(uint16_t x) const { return AMP_*(x - 2048); } - - private: - static const float AMP_ = 1.0f/2048.0f; - // AD 変換器の外部トリガに使うタイマ (TIM8) の設定 - // fSampling 標本化周波数 [kHz] - void SetTim8(float fSampling); - - // AD 変換器に関係のある GPIO の設定 - void SetGPIO(PinName pin); - - // コピー・コンストラクタ禁止のため - AdcF446_Polling(const AdcF446_Polling&); - // 代入演算子禁止のため - AdcF446_Polling& operator=(const AdcF446_Polling&); - }; -} -#endif // ADC_F446_POLLING2_HPP
--- a/ADDA_BasePolling/F446_DAC.hpp Fri Jan 17 02:04:09 2020 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -//-------------------------------------------------------- -// STM32F446 内蔵の DAC 用のクラス -// 出力端子: A2 (PA_4) -// -// 2020/01/12, Copyright (c) 2020 MIKAMI, Naoki -//-------------------------------------------------------- -#include "mbed.h" - -#ifndef DAC_F446_SINGLE_HPP -#define DAC_F446_SINGLE_HPP - -namespace Mikami -{ - class DacF446 - { - public: - // コンストラクタ, A2 に接続される CH1 のみを有効にする - DacF446() : da_(A2) { DAC->CR = DAC_CR_EN1; } - - virtual ~DacF446() {} - - // -1.0f <= data <= 1.0f - void Write(float data) { WriteDacCh1(ToUint16(data)); } - - // 0 <= data <= 4095 - void Write(uint16_t data) { WriteDacCh1(__USAT(data, BIT_WIDTH_)); } - - private: - static const int BIT_WIDTH_ = 12; - AnalogOut da_; - - // DAC の CH1 へ右詰めで出力する - void WriteDacCh1(uint16_t val) { DAC->DHR12R1 = val; } - - // 飽和処理を行い uint16_t 型のデータを戻り値とする - uint16_t ToUint16(float val) - { return __USAT((val + 1.0f)*2048.0f, BIT_WIDTH_); } - - // コピー・コンストラクタ禁止のため - DacF446(const DacF446&); - // 代入演算子禁止のため - DacF446& operator=(const DacF446&); - }; -} -#endif // DAC_F446_SINGLE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/F446_ADDA/F446_AdcBase.cpp Tue Jan 28 01:27:07 2020 +0000 @@ -0,0 +1,91 @@ +//------------------------------------------------------------- +// F446 内蔵 ADC2 のための抽象基底クラス +// +// 2020/01/28, Copyright (c) 2020 MIKAMI, Naoki +//------------------------------------------------------------- + +#include "F446_AdcBase.hpp" +#include "PeripheralPins.h" // PinMap_ADC を使う場合に必要 +#pragma diag_suppress 870 // マルチバイト文字使用の警告抑制のため +// PeripheralPins.c は以下よりたどって行けば取得可能 +// https://gitlab.exmachina.fr/fw-libs/mbed-os/tree/5.8.1 + +namespace Mikami +{ + // コンストラクタ + AdcF446_Base::AdcF446_Base(float fSampling, PinName pin) + { + SetGPIO(pin); // GPIO の設定 + + __HAL_RCC_ADC2_CLK_ENABLE(); // ADC2 にクロックを供給する + // __HAL_RCC_ADC2_CLK_ENABLE() の定義:stm32f4xx_hal_rcc_ex.h + + // 1 チャンネルのみ使用の設定 + myAdc_->SQR1 &= ~ADC_SQR1_L; + // pin に対応するチャンネルを使うための設定 + myAdc_->SQR3 = STM_PIN_CHANNEL(pinmap_function(pin, PinMap_ADC)); + // pinmap_function() のヘッダファイル: mbed\hal\pinmap.h + // STM_PIN_CHANNEL() の定義: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) の設定 + SetTim8(fSampling); + } + + // AD 変換器の外部トリガに使うタイマ (TIM8) の設定 + // fSampling 標本化周波数 [kHz] + void AdcF446_Base::SetTim8(float fSampling) + { + __HAL_RCC_TIM8_CLK_ENABLE(); // クロック供給. "stm32f4xx_hal_rcc.h" 参照 + TIM_TypeDef* const TIM = TIM8; + + TIM->CR2 = TIM_TRGO_UPDATE; // Update event を TRGO (trigger output) とする + + float arrF = (SystemCoreClock/fSampling)/1000.0f; + if (arrF >65535) + { + fprintf(stderr, "%8.2f kHz : 標本化周波数が低すぎます.\r\n", fSampling); + while (true) {} + } + TIM->ARR = floor(arrF + 0.5f) - 1; // Auto-reload レジスタの設定 + TIM->PSC = 0; // Prescaler の設定 + TIM->CR1 = TIM_CR1_CEN; // TIM8 を有効にする + } + + // AD 変換器に関係のある GPIO の設定 + void AdcF446_Base::SetGPIO(PinName pin) + { + // 各シンボルは stm32f4xx_hal_gpio.h で定義されている + // MODIFY_REG() マクロは stm32f4xx.h で定義されている + uint32_t nShift = STM_PIN(pin) << 1; + uint32_t moder = GPIO_MODE_ANALOG << nShift; + uint32_t mask = 0x03 << nShift; + switch (STM_PORT(pin)) + { + case 0: + if (__HAL_RCC_GPIOA_IS_CLK_DISABLED()) + __HAL_RCC_GPIOA_CLK_ENABLE(); // GPIOA にクロックを供給 + MODIFY_REG(GPIOA->MODER, mask, moder); // GPIOA のピンを設定 + break; + case 1: + if (__HAL_RCC_GPIOB_IS_CLK_DISABLED()) + __HAL_RCC_GPIOB_CLK_ENABLE(); // GPIOB にクロックを供給 + MODIFY_REG(GPIOB->MODER, mask, moder); // GPIOB のピンを設定 + break; + case 2: + if (__HAL_RCC_GPIOC_IS_CLK_DISABLED()) + __HAL_RCC_GPIOC_CLK_ENABLE(); // GPIOC にクロックを供給 + MODIFY_REG(GPIOC->MODER, mask, moder); // GPIOC のピンを設定 + break; + } + } + + // static メンバの実体 + ADC_TypeDef* const AdcF446_Base::myAdc_ = ADC2; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/F446_ADDA/F446_AdcBase.hpp Tue Jan 28 01:27:07 2020 +0000 @@ -0,0 +1,46 @@ +//------------------------------------------------------------- +// F446 内蔵 ADC2 のための抽象基底クラス(ヘッダ) +// +// 2020/01/28 Copyright (c) 2020 MIKAMI, Naoki +//------------------------------------------------------------- + +#include "mbed.h" + +#ifndef ADC_F446_BASE_HPP +#define ADC_F446_BASE_HPP + +namespace Mikami +{ + class AdcF446_Base + { + public: + // コンストラクタ + // fSampling 標本化周波数 [kHz] + // pin 入力ピンの名前 + AdcF446_Base(float fSampling, PinName pin); + + virtual ~AdcF446_Base() {} + + // AD 変換された値を読み込む + // -1.0f <= AD変換された値 < 1.0f + virtual float Read() const = 0; // 純粋仮想関数 + + protected: + static ADC_TypeDef* const myAdc_; // AD 変換器に対応するポインタ + float ToFloat(uint16_t x) const { return AMP_*(x - 2048); } + + private: + static const float AMP_ = 1.0f/2048.0f; + // AD 変換器の外部トリガに使うタイマ (TIM8) の設定 + // fSampling 標本化周波数 [kHz] + void SetTim8(float fSampling); + + // AD 変換器に関係のある GPIO の設定 + void SetGPIO(PinName pin); + + // コピー・コンストラクタ,代入演算子の禁止のため + AdcF446_Base(const AdcF446_Base&); + AdcF446_Base& operator=(const AdcF446_Base&); + }; +} +#endif // ADC_F446_BASE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/F446_ADDA/F446_AdcIntr.hpp Tue Jan 28 01:27:07 2020 +0000 @@ -0,0 +1,50 @@ +//------------------------------------------------------------- +// F446 内蔵 ADC2 を割込み方式で使うための派生クラス(ヘッダ) +// 基底クラス: AdcF446_Base +// +// 2020/01/28, Copyright (c) 2020 MIKAMI, Naoki +//------------------------------------------------------------- + +#include "F446_AdcBase.hpp" + +#ifndef ADC_F446_INTERRUPT_HPP +#define ADC_F446_INTERRUPT_HPP + +namespace Mikami +{ + class AdcF446_Intr : public AdcF446_Base + { + public: + // コンストラクタ + // fSampling 標本化周波数 [kHz] + // pin 入力ピンの名前 + AdcF446_Intr(float fSampling, PinName pin) + : AdcF446_Base(fSampling, pin) + { myAdc_->CR1 |= ADC_CR1_EOCIE; } // AD 変換終了割り込みを許可 + + virtual ~AdcF446_Intr() {} + + // 割込みベクタの設定と AD 変換割込みを有効にする + void SetIntrVec(void (*Func)()) + { + fp = Func; // 引数として渡された処理を割り当てる + NVIC_SetVector(ADC_IRQn, (uint32_t)Isr); // "core_cm4.h" 参照 + NVIC_EnableIRQ(ADC_IRQn); // "core_cm4.h" 参照 + } + + // AD 変換された値を読み込む + // -1.0f <= AD変換された値 < 1.0f + virtual float Read() const { return ToFloat(myAdc_->DR); } + + private: + static void (*fp)(); // 割込みサービス・ルーチンの中で実行される関数のポインタ + + // 割込みサービス・ルーチン,このクラスで使っている ADC であることを確認 + static void Isr() + { if ((myAdc_->SR & ADC_SR_EOC_Msk) == ADC_SR_EOC) fp(); } + }; + + // static メンバの実体 + void (*AdcF446_Intr::fp)(); +} +#endif // ADC_F446_INTERRUPT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/F446_ADDA/F446_AdcPolling.hpp Tue Jan 28 01:27:07 2020 +0000 @@ -0,0 +1,35 @@ +//------------------------------------------------------------- +// F446 内蔵 ADC2 をポーリング方式で使うための派生クラス(ヘッダ) +// 基底クラス: AdcF446_Base +// +// 2020/01/28, Copyright (c) 2020 MIKAMI, Naoki +//------------------------------------------------------------- + +#include "F446_AdcBase.hpp" + +#ifndef ADC_F446_POLLING_HPP +#define ADC_F446_POLLING_HPP + +namespace Mikami +{ + class AdcF446_Polling : public AdcF446_Base + { + public: + // コンストラクタ + // fSampling 標本化周波数 [kHz] + // pin 入力ピンの名前 + AdcF446_Polling(float fSampling, PinName pin) + : AdcF446_Base(fSampling, pin) {} + + virtual ~AdcF446_Polling() {} + + // AD 変換された値を読み込む + // -1.0f <= AD変換された値 < 1.0f + virtual float Read() const + { + while ((myAdc_->SR & ADC_SR_EOC) != ADC_SR_EOC) {} + return ToFloat(myAdc_->DR); + } + }; +} +#endif // ADC_F446_POLLING_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/F446_ADDA/F446_Dac.hpp Tue Jan 28 01:27:07 2020 +0000 @@ -0,0 +1,45 @@ +//-------------------------------------------------------- +// STM32F446 内蔵の DAC 用のクラス +// 出力端子: A2 (PA_4) +// +// 2020/01/28, Copyright (c) 2020 MIKAMI, Naoki +//-------------------------------------------------------- +#include "mbed.h" + +#ifndef DAC_F446_SINGLE_HPP +#define DAC_F446_SINGLE_HPP + +namespace Mikami +{ + class DacF446 + { + public: + // コンストラクタ, A2 に接続される CH1 のみを有効にする + DacF446() : da_(A2) { DAC->CR = DAC_CR_EN1; } + + virtual ~DacF446() {} + + // -1.0f <= data <= 1.0f + void Write(float data) { WriteDacCh1(ToUint16(data)); } + + // 0 <= data <= 4095 + void Write(uint16_t data) { WriteDacCh1(__USAT(data, BIT_WIDTH_)); } + + private: + static const int BIT_WIDTH_ = 12; + AnalogOut da_; + + // DAC の CH1 へ右詰めで出力する + void WriteDacCh1(uint16_t val) { DAC->DHR12R1 = val; } + + // 飽和処理を行い uint16_t 型のデータを戻り値とする + uint16_t ToUint16(float val) + { return __USAT((val + 1.0f)*2048.0f, BIT_WIDTH_); } + + // コピー・コンストラクタ禁止のため + DacF446(const DacF446&); + // 代入演算子禁止のため + DacF446& operator=(const DacF446&); + }; +} +#endif // DAC_F446_SINGLE_HPP
--- a/main.cpp Fri Jan 17 02:04:09 2020 +0000 +++ b/main.cpp Tue Jan 28 01:27:07 2020 +0000 @@ -15,14 +15,14 @@ // // PC 側のプログラムのフォルダ:プログラム\PC\F446_FFT_Analyzer // -// 2020/01/13, Copyright (c) 2020 MIKAMI, Naoki +// 2020/01/28, Copyright (c) 2020 MIKAMI, Naoki //--------------------------------------------------------------------- #include "mbed.h" #include <string> #include "Array.hpp" -#include "F446_ADC_Intr.hpp" -#include "F446_DAC.hpp" +#include "F446_AdcIntr.hpp" +#include "F446_Dac.hpp" #include "FFT_Analyzer.hpp" #include "DoubleBuffer.hpp" #include "Coefs_IIR6_LP_8k_Biquad.hpp" // 縦続形 IIR フィルタの係数