/*
  ******************************************************************************
  * @file    fxx_opa.c
  * @version V1.0.0
  * @date    2020
  * @brief   OPA std module driver.
  *          This file provides firmware functions to manage the following
  *          functionalities of the Operational Amplifier (OPA).
  *           @ Initialization and de-initialization functions
  *           @ IO operation functions
  *           @ Peripheral Control functions
  ******************************************************************************
*/
#include "fxx_std.h"
/************************************************************************
 * function   : OPA_Init
 * Description: opa initial with parameters. 
 * input : 
 *         uint32_t OPA_SEL: select OPA1/OPA2/OPA3
 *         OPA_InitTypeDef* Init: pointer to opa initial parameter structure
 ************************************************************************/
void OPA_Init(uint32_t OPA_SEL,OPA_InitTypeDef* Init)
{            
    __IO uint32_t *gu32RegCrx;
    uint8_t trim_value;
    uint32_t u32NvrTrimValue;

    /* Check the parameters */
    if(!IS_OPA_ALL_OPAX(OPA_SEL)) return;
    if(!IS_OPA_ALL_VINP(Init->VinPSel)) return;
    if(!IS_OPA_ALL_VINM(Init->VinMSel)) return;
    if(!IS_OPA_ALL_TRIM(Init->TrimEn)) return;

    if(OPA_SEL == OPA1)
        gu32RegCrx = &(OPA->OPA1_CSR);
    else if(OPA_SEL == OPA2)
        gu32RegCrx = &(OPA->OPA2_CSR);
    else if(OPA_SEL == OPA3)
        gu32RegCrx = &(OPA->OPA3_CSR);

    
    /* Select the Vin P */
    MODIFY_REG(*gu32RegCrx, OPA_CSR_VINPSEL_MASK, (Init->VinPSel)<<OPA_CSR_VINPSEL_POS);
    /* Select the Vin M */
    MODIFY_REG(*gu32RegCrx, OPA_CSR_VINMSEL_MASK, (Init->VinMSel)<<OPA_CSR_VINMSEL_POS);
    
    /* Enable the opa */
    SET_BIT(*gu32RegCrx, OPA_CSR_EN); 
    
    /* Trim the opa */    
    if(Init->TrimEn == OPA_CSR_TRIM_ENABLE)
    {
        /* Trim the OPA_CSR_CAL_H N channel */    
        SET_BIT(*gu32RegCrx, OPA_CSR_CAL_H);
        CLEAR_BIT(*gu32RegCrx, OPA_CSR_CAL_L);
        
        for(trim_value=0;trim_value<32;trim_value++)
        {
            MODIFY_REG(*gu32RegCrx,OPA_CSR_TRIM_HIGH_MASK,(trim_value)<<OPA_CSR_TRIM_HIGH_POS);
            System_Delay(1000);
            if(READ_BIT(*gu32RegCrx,OPA_CSR_CAL_OUT)) break;
        }        
        /* Trim the OPA_CSR_CAL_L P channel */    
        SET_BIT(*gu32RegCrx, OPA_CSR_CAL_L);
        CLEAR_BIT(*gu32RegCrx, OPA_CSR_CAL_H);
        
        for(trim_value=0;trim_value<32;trim_value++)
        {
            MODIFY_REG(*gu32RegCrx,OPA_CSR_TRIM_LOW_MASK,(trim_value)<<OPA_CSR_TRIM_LOW_POS);
            System_Delay(1000);
            if(READ_BIT(*gu32RegCrx,OPA_CSR_CAL_OUT)) break;
        }
    }
    else
    {
        /* Use the Trim value */    
        u32NvrTrimValue = *(volatile uint32_t*)(0x0008024C+(OPA_SEL-1)*4); //Read the OPA trim value;
        if(((~(u32NvrTrimValue>>16))&0xFFFF) != (u32NvrTrimValue&0xFFFF)) return;
        
        u32NvrTrimValue = u32NvrTrimValue & 0xFFFF;
            
        MODIFY_REG(*gu32RegCrx,OPA_CSR_TRIM_HIGH_MASK,((u32NvrTrimValue&0x1F)<<OPA_CSR_TRIM_HIGH_POS));
            
        MODIFY_REG(*gu32RegCrx,OPA_CSR_TRIM_LOW_MASK,(((u32NvrTrimValue>>5)&0x1F)<<OPA_CSR_TRIM_LOW_POS));    
        
        System_Delay(1000);
    }
    
    /* After trim enable the opa*/    
    SET_BIT(*gu32RegCrx, OPA_CSR_CAL_L);
    SET_BIT(*gu32RegCrx, OPA_CSR_CAL_H);
    
    return;
}

/************************************************************************
 * function   : OPA_Enable
 * Description: opa enable. 
 * input : 
 *         uint32_t OPA_SEL: select OPA1/OPA2/OPA3
 ************************************************************************/
void OPA_Enable(uint32_t OPA_SEL)
{    
    __IO uint32_t *gu32RegCrx;

    if(!IS_OPA_ALL_OPAX(OPA_SEL)) return;
    
    if(OPA_SEL == OPA1)
        gu32RegCrx = &(OPA->OPA1_CSR);
    else if(OPA_SEL == OPA2)
        gu32RegCrx = &(OPA->OPA2_CSR);
    else if(OPA_SEL == OPA3)
        gu32RegCrx = &(OPA->OPA3_CSR);
        
    /* Enable the opa */
    SET_BIT(*gu32RegCrx, OPA_CSR_EN); 
    
    return;
}
/************************************************************************
 * function   : OPA_Disable
 * Description: opa disable. 
 * input : 
 *         uint32_t OPA_SEL: select OPA1/OPA2/OPA3
 ************************************************************************/
void OPA_Disable(uint32_t OPA_SEL)
{        
    __IO uint32_t *gu32RegCrx;
    
    if(!IS_OPA_ALL_OPAX(OPA_SEL)) return;
    
    if(OPA_SEL == OPA1)
        gu32RegCrx = &(OPA->OPA1_CSR);
    else if(OPA_SEL == OPA2)
        gu32RegCrx = &(OPA->OPA2_CSR);
    else if(OPA_SEL == OPA3)
        gu32RegCrx = &(OPA->OPA3_CSR);
            
    /* Disable the opa */
    CLEAR_BIT(*gu32RegCrx, OPA_CSR_EN); 
    
    return;
}
