Dependents:   Demo_F446_AD_DA_Single F446ZE-mbed-devfiles

Files at this revision

API Documentation at this revision

Comitter:
MikamiUitOpen
Date:
Tue Feb 21 00:40:10 2017 +0000
Commit message:
1

Changed in this revision

F446_ADC_Interrupt_Single.hpp Show annotated file Show diff for this revision Revisions of this file
F446_ADC_Single.cpp Show annotated file Show diff for this revision Revisions of this file
F446_ADC_Single.hpp Show annotated file Show diff for this revision Revisions of this file
F446_DAC_Single.cpp Show annotated file Show diff for this revision Revisions of this file
F446_DAC_Single.hpp Show annotated file Show diff for this revision Revisions of this file
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