//-----------------------------------------------------------
// タイマを使った正確な同期の実現, TIM7 を使用
//
//  2022/10/17, Copyright (c) 2022 MIKAMI, Naoki
//-----------------------------------------------------------

#include "MyTicker7.hpp"

namespace Mikami
{
    // コンストラクタ
    //      period  時間間隔 [μs]
    MyTicker7::MyTicker7(float period)
    {
        // このクラスのオブジェクトの多重生成禁止のため
        MBED_ASSERT(!created_);
        created_ = true;

        __HAL_RCC_TIM7_CLK_ENABLE();   // クロック供給. "stm32f4xx_hal_rcc.h" 参照

        uint32_t maxClock;
        if ((RCC->DCKCFGR & RCC_DCKCFGR_TIMPRE) == RCC_DCKCFGR_TIMPRE)
            maxClock = SystemCoreClock;
        else
            maxClock = SystemCoreClock/2;

        float arrF = period*maxClock/1000000.0f + 0.5f;
        MBED_ASSERT(arrF < 32768.5f);
        MY_TIM_->ARR = (uint32_t)arrF - 1;  // Auto-reload レジスタの設定
        MY_TIM_->PSC = 0;               // Prescaler の設定
        MY_TIM_->CR1 = TIM_CR1_CEN;     // TIM7 を有効にする
    }

    // コンストラクタで設定した時間が経過するまで待つ
    void MyTicker7::Sync()
    {
        // タイマの Update イベントが発生するまで待つ
        while ((MY_TIM_->SR & TIM_SR_UIF_Msk) != TIM_SR_UIF) {}
        // Update interrupt flag をクリア
        MY_TIM_->SR &= ~TIM_SR_UIF;
    }

    // クラス内 ISR で実行する関数の割当て，割込みを有効にする
    void MyTicker7::Attach(void (*Func)())
    {
        NVIC_SetVector(TIM7_IRQn, (uint64_t)Isr);
        NVIC_EnableIRQ(TIM7_IRQn);
        
        fp = Func;  // 外部で定義されている関数を割り当てる

        Enable();   // Update 割込みを有効にする
    }

    // 割込みサービス･ルーチン（ISR）
    void MyTicker7::Isr()
    {
        MY_TIM_->SR &= ~TIM_SR_UIF; // Update 割込みをクリア
        fp();                       // 外部で定義されている関数を実行
    }

    // static オブジェクトの実体
    TIM_TypeDef* const MyTicker7::MY_TIM_ = TIM7;
    void (*MyTicker7::fp)();
    bool MyTicker7::created_ = false;
}
