Dependents: Demo_F446_AD_DA_Single F446ZE-mbed-devfiles
Revision 0:2a5690e56a16, committed 2017-02-21
- Comitter:
- MikamiUitOpen
- Date:
- Tue Feb 21 00:40:10 2017 +0000
- Commit message:
- 1
Changed in this revision
diff -r 000000000000 -r 2a5690e56a16 F446_ADC_Interrupt_Single.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/F446_ADC_Interrupt_Single.hpp Tue Feb 21 00:40:10 2017 +0000 @@ -0,0 +1,53 @@ +//-------------------------------------------------------------- +// AD Conversion by interrupt using ADC2 or ADC3 on STM32F446 +// +// STM32F446 の ADC2 または ADC3 を使って割り込みにより +// アナログ信号を入力するクラス +// AdcSingle クラスの派生クラス +// +// 2017/02/16, Copyright (c) 2017 MIKAMI, Naoki +//-------------------------------------------------------------- + +#ifndef F446_ADC_SINGLE_INTERRUPT_HPP +#define F446_ADC_SINGLE_INTERRUPT_HPP + +#include "F446_ADC_Single.hpp" + +namespace Mikami +{ + class AdcSingle_Intr : public AdcSingle + { + public: + AdcSingle_Intr(PinName pin, int frequency) + : AdcSingle(pin, frequency) + { + if (pin == A0) ADC2->CR1 |= ADC_CR1_EOCIE; + else ADC3->CR1 |= ADC_CR1_EOCIE; + } + + virtual ~AdcSingle_Intr() {} + + // -1.0f <= ad1, ad2 <= 1.0f + virtual float Read() { return ToFloat(adc_->DR); } + + // 0 <= ad1, ad2 <= 4095 + virtual uint16_t ReadUint() { return adc_->DR; } + + // Set interrupt vector and enable IRQ of ADC + void SetIntrVec(void (*Func)()) + { + NVIC_SetVector(ADC_IRQn, (uint32_t)Func); // See "cmsis_nvic.h" + NVIC_EnableIRQ(ADC_IRQn); // See "core_cm4.h" + } + + void DisableAdcIntr() + { NVIC_DisableIRQ(ADC_IRQn); } + + private: + // for inhibition of copy constructor + AdcSingle_Intr(const AdcSingle_Intr&); + // for inhibition of substitute operator + AdcSingle_Intr& operator=(const AdcSingle_Intr&); + }; +} +#endif // F446_ADC_DUAL_INTERRUPT_HPP
diff -r 000000000000 -r 2a5690e56a16 F446_ADC_Single.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/F446_ADC_Single.cpp Tue Feb 21 00:40:10 2017 +0000 @@ -0,0 +1,98 @@ +//------------------------------------------------------------ +// AD Conversion by polling using ADC2 or ADC3 on STM32F446 +// +// STM32F446 の ADC2, ADC3 を使ってポーリングによりアナログ信号を +// 入力するクラス +// A0 (PA_0) : ADC2 CH0 +// A1 (PA_1) : ADC3 CH1 +// +// 2017/02/16, Copyright (c) 2017 MIKAMI, Naoki +//------------------------------------------------------------ + +#include "F446_ADC_Single.hpp" + +namespace Mikami +{ + AdcSingle::AdcSingle(PinName pin, int frequency) + { + if ( (pin != A0) && (pin != A1) ) + { + fprintf(stderr, "Invalid pin name\r\n"); + return; + } + + // PA0 または PA1 を ADC 入力として使うための設定 + __HAL_RCC_GPIOA_CLK_ENABLE(); + GPIO_InitTypeDef gpioInit; + gpioInit.Pin = (pin == A0) ? GPIO_PIN_0 : GPIO_PIN_1; + gpioInit.Mode = GPIO_MODE_ANALOG; + gpioInit.Pull = GPIO_NOPULL; + gpioInit.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + HAL_GPIO_Init(GPIOA, &gpioInit); + + if (pin == A0) // ADC2 の設定 (入力ポート:PA0) + { + __HAL_RCC_ADC2_CLK_ENABLE(); + adc_ = ADC2; + adc_->SQR3 = 0x0; // CH0 を使う + fpWait = &AdcSingle::WaitDone2; + } + else // ADC3 の設定 (入力ポート:PA1) + { + __HAL_RCC_ADC3_CLK_ENABLE(); + adc_ = ADC3; + adc_->SQR3 = 0x1; // CH1 を使う + fpWait = &AdcSingle::WaitDone3; + } + adc_->CR1 = 0x0; + adc_->CR2 = ADC_EXTERNALTRIGCONVEDGE_RISING // 外部トリガの立ち上がりで開始される + | ADC_EXTERNALTRIGCONV_T8_TRGO // 外部トリガ: Timer8 TRGO event + | ADC_CR2_ADON; // ADC を有効にする + + // ADC 共通の設定 + ADC->CCR = 0x0; // 念のため + + // AD 変換器の外部トリガに使うタイマ (TIM8) の設定 + SetTim8(frequency); + } + + float AdcSingle::Read() + { + (this->*fpWait)(); + return ToFloat(adc_->DR); + } + + uint16_t AdcSingle::ReadUint() + { + (this->*fpWait)(); + return adc_->DR; + } + + void AdcSingle::SetTim8(int frequency) + { + __HAL_RCC_TIM8_CLK_ENABLE(); // Supply clock. See "stm32f4xx_hal_rcc.h" + SystemCoreClockUpdate(); // Update core clock. See "system_stm32f4xx.h" + TIM_TypeDef* const myTim = TIM8; + + myTim->CR2 = TIM_CR2_MMS_1; // Update event: as trigger out + + uint32_t psc = 0; + uint16_t mul = 1; + uint32_t arr; + while (true) + { + arr = SystemCoreClock/(mul*frequency); + if (arr <= 65536) break; + psc++; + mul++; + if (psc > 65535) + { + fprintf(stderr, "Sampling frequency: too low.\r\n"); + while (true) {} + } + } + myTim->ARR = arr - 1; // Auto-reload + myTim->PSC = psc; // Prescaler + myTim->CR1 = TIM_CR1_CEN; // Enable TIM8 + } +}
diff -r 000000000000 -r 2a5690e56a16 F446_ADC_Single.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/F446_ADC_Single.hpp Tue Feb 21 00:40:10 2017 +0000 @@ -0,0 +1,67 @@ +//------------------------------------------------------------ +// AD Conversion by polling using ADC2 or ADC3 on STM32F446 +// ---- Header ---- +// +// STM32F446 の ADC2, ADC3 を使ってポーリングによりアナログ信号を +// 入力するクラス(ヘッダ) +// A0 (PA_0) : ADC2 CH0 +// A1 (PA_1) : ADC3 CH1 +// +// 2017/02/16, Copyright (c) 2017 MIKAMI, Naoki +//------------------------------------------------------------ + +#include "mbed.h" + +#ifndef STM32F446xx +#error Select NUCLEO-F446RE. +#endif + +#include "F446_DAC_Single.hpp" + +#ifndef F446_ADC_SINGLE_HPP +#define F446_ADC_SINGLE_HPP + +namespace Mikami +{ + class AdcSingle + { + public: + // Constructor + // frequency: 標本化周波数 + explicit AdcSingle(PinName pin, int frequency); + + virtual ~AdcSingle() {} + + // -1.0f <= ad1, ad2 <= 1.0f + // ad1: left, ad2: right + virtual float Read(); + + // 0 <= ad1, ad2 <= 4095 + // ad1: left, ad2: right + virtual uint16_t ReadUint(); + + protected: + ADC_TypeDef *adc_; + + float ToFloat(uint16_t x) + { return AMP_*(x - 2048); } + + private: + static const float AMP_ = 1.0f/2048.0f; + + void (AdcSingle::*fpWait)(); + + // AD 変換が完了するまで待つ + void WaitDone2() { while ((ADC2->SR & ADC_SR_EOC) != ADC_SR_EOC); } + void WaitDone3() { while ((ADC3->SR & ADC_SR_EOC) != ADC_SR_EOC); } + + // AD 変換器の外部トリガに使うタイマ (TIM8) の設定 + void SetTim8(int frequency); + + // for inhibition of copy constructor + AdcSingle(const AdcSingle&); + // for inhibition of substitute operator + AdcSingle& operator=(const AdcSingle&); + }; +} +#endif // F446_ADC_SINGLE_HPP
diff -r 000000000000 -r 2a5690e56a16 F446_DAC_Single.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/F446_DAC_Single.cpp Tue Feb 21 00:40:10 2017 +0000 @@ -0,0 +1,56 @@ +//-------------------------------------------------------- +// Class for buit-in single DAC on STM32F446 +// +// STM32F446 内蔵の DAC 用のクラス +// DAC_OUT1: A2 (PA_4) +// DAC_OUT2: D13 (PA_5) +// +// 2017/02/21, Copyright (c) 2017 MIKAMI, Naoki +//-------------------------------------------------------- + +#include "F446_DAC_Single.hpp" + +namespace Mikami +{ + DacSingle::DacSingle(PinName pin) : da_(pin) + { + if (pin == A2) + { + DAC->CR = DAC_CR_EN1 | DAC_CR_TEN1 | DAC_CR_TSEL1; + fpWriteDac = &DacSingle::WriteDac1; + } + else + { + DAC->CR = DAC_CR_EN2 | DAC_CR_TEN2 | DAC_CR_TSEL2; + fpWriteDac = &DacSingle::WriteDac2; + } + } + + // Write single-channel data + void DacSingle::WriteDac1(uint16_t val) + { + DAC->DHR12R1 = val; + DAC->SWTRIGR = DAC_SWTRIGR_SWTRIG1; + } + void DacSingle::WriteDac2(uint16_t val) + { + DAC->DHR12R2 = val; + DAC->SWTRIGR = DAC_SWTRIGR_SWTRIG2; + } + + void DacSingle::ScfClock(uint32_t clock) + { + PwmOut clockSCF(D12); // PA6 + + uint32_t arr; + if ((RCC->DCKCFGR & RCC_DCKCFGR_TIMPRE) == RCC_DCKCFGR_TIMPRE) + arr = SystemCoreClock/clock - 1; + else + arr = SystemCoreClock/(2*clock) - 1; + TIM3->ARR = arr; + TIM3->PSC = 0; + + // Set capture/compare register 1 + TIM3->CCR1 = (TIM3->ARR + 1)/2; + } +}
diff -r 000000000000 -r 2a5690e56a16 F446_DAC_Single.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/F446_DAC_Single.hpp Tue Feb 21 00:40:10 2017 +0000 @@ -0,0 +1,63 @@ +//-------------------------------------------------------- +// Class for buit-in single DAC on STM32F446 ---- Header +// TIM3 is used for clock to external SCF +// +// STM32F446 内蔵の DAC 用のクラス(ヘッダ) +// TIM3 を外付けの SCF のクロックとして使用 +// A2 (PA_4): 左 ---- デフォルト +// D13 (PA_5): 右 +// +// 2017/02/21, Copyright (c) 2017 MIKAMI, Naoki +//-------------------------------------------------------- + +#include "mbed.h" + +#ifndef STM32F446xx +#error Select NUCLEO-F446RE. +#endif + +#ifndef F446_DAC_SINGLE_HPP +#define F446_DAC_SINGLE_HPP + +namespace Mikami +{ + class DacSingle + { + public: + // Constructor + DacSingle(PinName pin = A2); + + virtual ~DacSingle() {} + + // -1.0f <= data <= 1.0f + void Write(float data) { WriteDac(ToUint16(data)); } + + // 0 <= data1<= 4095 + void Write(uint16_t data) { WriteDac(__USAT(data, BIT_WIDTH_)); } + + // Set TIM3 for clock of switched-capacitor filter + void ScfClock(uint32_t clock); + + private: + void (DacSingle::*fpWriteDac)(uint16_t); + + static const int BIT_WIDTH_ = 12; + AnalogOut da_; + + // Write single-channel data + void WriteDac1(uint16_t val); + void WriteDac2(uint16_t val); + + void WriteDac(uint16_t val) { (this->*fpWriteDac)(val); } + + // Saturate float to an unsigned 16-bit value + uint16_t ToUint16(float val) + { return __USAT((val + 1.0f)*2047.0f, BIT_WIDTH_); } + + // for inhibition of copy constructor + DacSingle(const DacSingle&); + // for inhibition of substitute operator + DacSingle& operator=(const DacSingle&); + }; +} +#endif // F446_DAC_SINGLEL_HPP