/** * @file adc.c * @author chipsea * @brief Contains all functions support for adc driver * @version 0.1 * @date 2020-11-30 * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd. * @note */ #include #include "error.h" #include "gpio.h" #include "pwrmgr.h" #include "clock.h" #include "adc.h" #include "log.h" #include "jump_function.h" #include "halPeripheral.h" typedef struct _adc_Contex_t { bool enable; uint8_t all_channel; uint8_t chs_en_shadow; bool continue_mode; //sysclk_t clk_src; uint16_t adc_cal_postive; uint16_t adc_cal_negtive; adc_Hdl_t evt_handler; } adc_Ctx_t; static adc_Ctx_t mAdc_Ctx = { .enable = FALSE, .all_channel = 0x00, .chs_en_shadow = 0x00, .continue_mode = FALSE, .adc_cal_postive = 0xFFF, .adc_cal_negtive = 0xFFF, .evt_handler = NULL }; #define ADC_SAMPING_NUM 32 #define ADC_MAX_OFFSET 64 #define FILTER_SIZE 4 uint16_t filter(uint32_t base,int ch,int n) { char count,j; int offset; uint16_t max ,min ; uint16_t value_buf[FILTER_SIZE]; int sum=0; offset = n; for (count=0;count>16)&0xfff); offset ++; } max = value_buf[0]; min = value_buf[0]; sum = value_buf[0]; for(j=1;j value_buf[j])? max : value_buf[j]; min = (min > value_buf[j])? value_buf[j] : min ; sum += value_buf[j]; } sum -= (max + min); return (uint16_t)(sum>>1); } /** * @fn HalAdcLoadCalibrationValue * @brief Read calibration values from Flash * @param none * @return none */ static void HalAdcLoadCalibrationValue(void) { uint32_t adc_cal = read_reg(SPIF_RSVD1_ADC_CALIBRATE); mAdc_Ctx.adc_cal_negtive = (uint16_t)(adc_cal&0x0fff); mAdc_Ctx.adc_cal_postive = (uint16_t)((adc_cal>>16)&0x0fff); LOG("AD_CAL[%x %x]\n",mAdc_Ctx.adc_cal_negtive,mAdc_Ctx.adc_cal_postive); if((mAdc_Ctx.adc_cal_negtive < 0x733) || (mAdc_Ctx.adc_cal_negtive > 0x8cc) || (mAdc_Ctx.adc_cal_postive < 0x733) || (mAdc_Ctx.adc_cal_postive > 0x8cc)) { mAdc_Ctx.adc_cal_negtive = 0xfff; mAdc_Ctx.adc_cal_postive = 0xfff; LOG("->AD_CAL[%x %x]\n",mAdc_Ctx.adc_cal_negtive, mAdc_Ctx.adc_cal_postive); } } GpioPin_t s_pinmap[ADC_CH_NUM] = { GPIO_DUMMY, //ADC_CH0 =0, GPIO_DUMMY, //ADC_CH1 =1, P11, //ADC_CH1N =2, P23, //ADC_CH1P =3, P24, //ADC_CH2N =4, P14, //ADC_CH2P =5, P15, //ADC_CH3N =6, P20, //ADC_CH3P =7, GPIO_DUMMY, //ADC_CH_VOICE =8, }; /** * @fn SetSamplingResolution * @brief Set the sampling resolution * @param channel * @param is_high_resolution * @param is_differential_mode * @return none */ static void SetSamplingResolution(AdcChannel_t channel, bool is_high_resolution) { uint8_t aio = 0; switch(channel) { case ADC_CH1N_P11: aio = 0; break; case ADC_CH1P_P23: aio = 1; break; case ADC_CH2N_P24: aio = 2; break; case ADC_CH2P_P14: aio = 3; break; case ADC_CH3N_P15: aio = 4; break; case ADC_CH3P_P20: aio = 7; break; default: return; } if(is_high_resolution) { subWriteReg(&(AP_AON->PMCTL2_1),(aio+8),(aio+8),0); subWriteReg(&(AP_AON->PMCTL2_1),aio,aio,1); } else { subWriteReg(&(AP_AON->PMCTL2_1),(aio+8),(aio+8),1); subWriteReg(&(AP_AON->PMCTL2_1),aio,aio,0); } } /** * @fn SetSamplingResolutionAuto * @brief Set the automatic sampling resolution * @param channel * @param is_high_resolution * @param is_differential_mode * @return none */ static void SetSamplingResolutionAuto(uint8_t channel, uint8_t is_high_resolution) { uint8_t i_channel; AdcChannel_t a_channel; AP_AON->PMCTL2_1 = 0x00; for(i_channel =MIN_ADC_CH;i_channel<=MAX_ADC_CH;i_channel++) { if(channel & BIT(i_channel)) { a_channel = (AdcChannel_t)i_channel; SetSamplingResolution(a_channel, (is_high_resolution & BIT(i_channel))); } } } /** * @fn DisableAnalogPin * @brief disable analog pin * @param channel * @return none */ static void DisableAnalogPin(AdcChannel_t channel) { int index = (int)channel; GpioPin_t pin = s_pinmap[index]; if(pin == GPIO_DUMMY) return; HalGpioAnalogConfig(pin,Bit_DISABLE); HalGpioPinInit(pin,GPIO_INPUT); //ie=0,oen=1 set to imput HalGpioPupdConfig(pin,GPIO_FLOATING); // } /** * @fn ClearAdcConfig * @brief Clear configuration * @param none * @return none */ static void ClearAdcConfig(void) { mAdc_Ctx.all_channel = 0x00; mAdc_Ctx.chs_en_shadow = 0x00; mAdc_Ctx.continue_mode = FALSE; mAdc_Ctx.evt_handler = NULL; } /** * @fn HalAdcIRQHandler * @brief This function process for adc interrupt * @param none * @return none */ volatile int flag = 0; void __attribute__((used)) HalAdcIRQHandler(void) { int ch,status,ch2,n; uint16_t adc_data[MAX_ADC_SAMPLE_SIZE]; status = GET_IRQ_STATUS; uint32_t adc_pointer; uint8_t filter_count =0; for (ch = MIN_ADC_CH; ch <= MAX_ADC_CH; ch++) { if((mAdc_Ctx.all_channel & BIT(ch)) &&(status & BIT(ch))) { ch2=(ch%2)?(ch-1):(ch+1); if(mAdc_Ctx.continue_mode == FALSE) { AP_ADCC->intr_mask &= ~ BIT(ch); //MASK coresponding channel mAdc_Ctx.all_channel &= ~BIT(ch);//disable channel } if (status & BIT(ch)) { AP_ADCC->intr_mask &= ~BIT(ch); switch(ch) { case ADC_CH0: adc_pointer = ADC_CH1_POINTER; break; case ADC_CH1: adc_pointer = ADC_CH2_POINTER; break; case ADC_CH2: adc_pointer = ADC_CH3_POINTER; break; case ADC_CH3: adc_pointer = ADC_CH4_POINTER; break; case ADC_CH4: adc_pointer = ADC_CH5_POINTER; break; case ADC_CH9: adc_pointer = ADC_CH6_POINTER; break; default: break; } if(adc_pointer <= 0 || adc_pointer > ADC_MAX_OFFSET) { adc_pointer = ADC_SAMPING_NUM ; } else if(adc_pointer < ADC_SAMPING_NUM) { adc_pointer += ADC_MAX_OFFSET; adc_pointer -= ADC_SAMPING_NUM; }else{ adc_pointer -= ADC_SAMPING_NUM; } adc_pointer = adc_pointer >>1; filter_count =0; for (n = 0; n < (MAX_ADC_SAMPLE_SIZE>>2); n++) { adc_data[n] = filter(adc_pointer,ch,filter_count); filter_count +=2; if((adc_pointer + filter_count) > ADC_MAX_OFFSET ) { adc_pointer =0; filter_count =0; } } AP_ADCC->intr_clear = BIT(ch); if(mAdc_Ctx.enable == FALSE) continue; if (mAdc_Ctx.evt_handler){ AdcEvt_t evt; evt.type = HAL_ADC_EVT_DATA; evt.ch = (AdcChannel_t)ch2; evt.data = adc_data; evt.size = (MAX_ADC_SAMPLE_SIZE) >> 2; mAdc_Ctx.evt_handler(&evt); } AP_ADCC->intr_mask |= BIT(ch); } } } if((mAdc_Ctx.all_channel == 0) && (mAdc_Ctx.continue_mode == FALSE))// { HalAdcStop(); } } /** * @fn AdcWakeupHdl * @brief Set the ADC interrupt priority * @param none * @return none */ static void AdcWakeupHdl(void) { NVIC_SetPriority((IRQn_Type)ADCC_IRQn, IRQ_PRIO_HAL); } /** * @fn HalAdcInit * @brief This function process for adc initial * @param none * @return none * @note mode: adc sample mode select;1:SAM_MANNUAL(mannual mode),0:SAM_AUTO(auto mode) * ADC_CH_e adc_pin: adc pin select;ADC_CH0~ADC_CH7 and ADC_CH_VOICE * ADC_SEMODE_e semode: signle-ended mode negative side enable; 1:SINGLE_END(single-ended mode) 0:DIFF(Differentail mode) * IO_CONTROL_e amplitude: input signal amplitude, 0:BELOW_1V,1:UP_1V */ void HalAdcInit(void) { hal_pwrmgr_register(MOD_ADCC,NULL,AdcWakeupHdl); ClearAdcConfig(); HalAdcLoadCalibrationValue(); mAdc_Ctx.enable = TRUE; } /** * @fn HalAdcClockConfig * @brief This function process for adc clock * @param clk - clock * @return none */ int HalAdcClockConfig(AdcClockSel_t clk){ if(mAdc_Ctx.enable == FALSE){ return ERR_NOT_REGISTED; } if(clk > HAL_ADC_CLOCK_320K) { return ERR_INVALID_PARAM; } subWriteReg(0x4000F000 + 0x7c,2,1,clk); return SUCCESS; } /** * @fn HalAdcStart * @brief start * @param none * @return none */ int HalAdcStart(void) { uint8_t all_channel2 = (((mAdc_Ctx.chs_en_shadow&0x80)>>1)|\ ((mAdc_Ctx.chs_en_shadow&0x40)<<1)|\ ((mAdc_Ctx.chs_en_shadow&0x20)>>1)|\ ((mAdc_Ctx.chs_en_shadow&0x10)<<1)|\ ((mAdc_Ctx.chs_en_shadow&0x08)>>1)|\ ((mAdc_Ctx.chs_en_shadow&0x04)<<1)); if(mAdc_Ctx.enable == FALSE){ return ERR_NOT_REGISTED; } hal_pwrmgr_lock(MOD_ADCC); JUMP_FUNCTION(ADCC_IRQ_HANDLER) = (uint32_t)&HalAdcIRQHandler; //ENABLE_ADC; for(int i=MIN_ADC_CH; i<=MAX_ADC_CH; i++) { if(all_channel2 & (BIT(i))) { switch (i) { case ADC_CH1N_P11: AP_PCRM->ADC_CTL1 |= BIT(20); break; case ADC_CH1P_P23: AP_PCRM->ADC_CTL1 |= BIT(4); break; case ADC_CH2N_P24: AP_PCRM->ADC_CTL2 |= BIT(20); break; case ADC_CH2P_P14: AP_PCRM->ADC_CTL2 |= BIT(4); break; case ADC_CH3N_P15: AP_PCRM->ADC_CTL3 |= BIT(20); break; case ADC_CH3P_P20: AP_PCRM->ADC_CTL3 |= BIT(4); break; } } } AP_PCRM->ANA_CTL |= BIT(3); AP_PCRM->ANA_CTL |= BIT(0);//new //ADC_IRQ_ENABLE; NVIC_EnableIRQ((IRQn_Type)ADCC_IRQn); //ENABLE_ADC_INT; AP_ADCC->intr_mask = mAdc_Ctx.all_channel; //disableSleep(); return SUCCESS; } /** * @fn HalAdcChannelConfig * @brief adc channel config * @param clk - clock * @return none */ int HalAdcChannelConfig(AdcCfg_t cfg, adc_Hdl_t evt_handler) { uint8_t i; if(mAdc_Ctx.enable == FALSE) { return ERR_NOT_REGISTED; } if(evt_handler == NULL) { return ERR_INVALID_PARAM; } if((cfg.channel_flag & BIT(0)) || (cfg.channel_flag & BIT(1))) { return ERR_NOT_SUPPORTED; } ClearAdcConfig(); AP_AON->PMCTL2_1 = 0x00; AP_PCRM->ANA_CTL &= ~BIT(0); AP_PCRM->ANA_CTL &= ~BIT(3); hal_clk_gate_disable(MOD_ADCC); hal_clk_reset(MOD_ADCC); mAdc_Ctx.continue_mode = cfg.is_continue_mode; mAdc_Ctx.all_channel = cfg.channel_flag & 0x03; for(i=2;i<8;i++){ if(cfg.channel_flag & BIT(i)){ if(i%2){ mAdc_Ctx.all_channel |= BIT(i-1); } else{ mAdc_Ctx.all_channel |= BIT(i+1); } } } mAdc_Ctx.chs_en_shadow = mAdc_Ctx.all_channel; if((AP_PCR->SW_CLK & BIT(MOD_ADCC)) == 0) { hal_clk_gate_enable(MOD_ADCC); } //CLK_1P28M_ENABLE; AP_PCRM->CLKSEL |= BIT(6); //ENABLE_XTAL_OUTPUT; //enable xtal 16M output,generate the 32M dll clock AP_PCRM->CLKHF_CTL0 |= BIT(18); //ENABLE_DLL; //enable DLL AP_PCRM->CLKHF_CTL1 |= BIT(7); //ADC_DBLE_CLOCK_DISABLE; //disable double 32M clock,we are now use 32M clock,should enable bit<13>, diable bit<21> AP_PCRM->CLKHF_CTL1 &= ~BIT(21);//check //subWriteReg(0x4000F044,21,20,3); //ADC_CLOCK_ENABLE; //adc clock enbale,always use clk_32M AP_PCRM->CLKHF_CTL1 |= BIT(13); //subWriteReg(0x4000f07c,4,4,1); //set adc mode,1:mannual,0:auto mode AP_PCRM->ADC_CTL4 |= BIT(4); // AP_PCRM->ADC_CTL4 |= BIT(3); AP_PCRM->ADC_CTL4 |= BIT(0); // AP_PCRM->ADC_CTL4 &= ~BIT(3); SetSamplingResolutionAuto(cfg.channel_flag, cfg.is_high_resolution); AP_PCRM->ADC_CTL0 &= ~BIT(20); AP_PCRM->ADC_CTL0 &= ~BIT(4); AP_PCRM->ADC_CTL1 &= ~BIT(20); AP_PCRM->ADC_CTL1 &= ~BIT(4); AP_PCRM->ADC_CTL2 &= ~BIT(20); AP_PCRM->ADC_CTL2 &= ~BIT(4); AP_PCRM->ADC_CTL3 &= ~BIT(20); AP_PCRM->ADC_CTL3 &= ~BIT(4); AP_PCRM->ANA_CTL &= ~BIT(23);//disable micbias AP_PCRM->ADC_CTL4 &= ~BIT(4); //enable auto mode mAdc_Ctx.evt_handler = evt_handler; for(i=MIN_ADC_CH;i<=MAX_ADC_CH;i++){ if(cfg.channel_flag & BIT(i)){ GpioPin_t pin = s_pinmap[i]; HalGpioPupdConfig(pin,GPIO_FLOATING); HalGpioDsControl(pin, Bit_ENABLE); HalGpioAnalogConfig(pin, Bit_ENABLE); switch (i) { case 0: // AP_PCRM->ADC_CTL0 |= BIT(20); break; case 1: // AP_PCRM->ADC_CTL0 |= BIT(4); AP_ADCC->compare_cfg[0] = (ADC_SAMPING_NUM<<24); break; case 2: // AP_PCRM->ADC_CTL1 |= BIT(20); AP_ADCC->compare_cfg[1] = (ADC_SAMPING_NUM<<24); break; case 3: // AP_PCRM->ADC_CTL1 |= BIT(4); AP_ADCC->compare_cfg[2] = (ADC_SAMPING_NUM<<24); break; case 4: // AP_PCRM->ADC_CTL2 |= BIT(20); AP_ADCC->compare_cfg[3] = (ADC_SAMPING_NUM<<24); break; case 5: // AP_PCRM->ADC_CTL2 |= BIT(4); AP_ADCC->compare_cfg[4] = (ADC_SAMPING_NUM<<24); break; case 6: // AP_PCRM->ADC_CTL3 |= BIT(20); AP_ADCC->compare_cfg[5] = (ADC_SAMPING_NUM<<24); break; case 7: // AP_PCRM->ADC_CTL3 |= BIT(4); AP_ADCC->compare_cfg[6] = (ADC_SAMPING_NUM<<24); break; default: break; } } } return SUCCESS; } /** * @fn HalAdcStop * @brief stop * @param none * @return none */ int HalAdcStop(void) { int i; uint8_t all_channel2 = (((mAdc_Ctx.chs_en_shadow&0x80)>>1)|\ ((mAdc_Ctx.chs_en_shadow&0x40)<<1)|\ ((mAdc_Ctx.chs_en_shadow&0x20)>>1)|\ ((mAdc_Ctx.chs_en_shadow&0x10)<<1)|\ ((mAdc_Ctx.chs_en_shadow&0x08)>>1)|\ ((mAdc_Ctx.chs_en_shadow&0x04)<<1)); if(mAdc_Ctx.enable == FALSE) { return ERR_NOT_REGISTED; } //MASK_ADC_INT; AP_ADCC->intr_mask = 0x1ff; NVIC_DisableIRQ((IRQn_Type)ADCC_IRQn); JUMP_FUNCTION(ADCC_IRQ_HANDLER) = 0; AP_ADCC->intr_clear = 0x1FF; //DISABLE_ADC; AP_PCRM->ANA_CTL &= ~BIT(3); //ADC_CLOCK_DISABLE; // if(g_system_clk != SYS_CLK_DBL_32M) // { AP_PCRM->CLKHF_CTL1 &= ~BIT(13); // } for(i =MIN_ADC_CH; i<= MAX_ADC_CH; i++){ if(all_channel2 & BIT(i)){ DisableAnalogPin((AdcChannel_t)i); } } AP_PCRM->ANA_CTL &= ~BIT(0);//Power down analog LDO hal_clk_reset(MOD_ADCC); hal_clk_gate_disable(MOD_ADCC); ClearAdcConfig(); //enableSleep(); hal_pwrmgr_unlock(MOD_ADCC); return SUCCESS; } const unsigned int adc_Lambda[MAX_ADC_CH - MIN_ADC_CH + 1] = { 4519,//P11 4308,//P23 4263,//P24 4482,//P14 4180,//P15 4072,//P20 }; /** * @fn HalAdcValueCal * @brief This function calibration ADC results * @param * @return none */ int32_t HalAdcValueCal(AdcChannel_t ch,uint16_t* buf, uint32_t size, uint8_t high_resol) { uint32_t i; int adc_sum = 0; volatile int32_t result = 0; uint16_t adc_cal_postive = mAdc_Ctx.adc_cal_postive; uint16_t adc_cal_negtive = mAdc_Ctx.adc_cal_negtive; if(ch< MIN_ADC_CH || ch > MAX_ADC_CH) { return ERR_INVALID_PARAM; } for (i = 0; i < size; i++) { adc_sum += (buf[i]&0xfff); } HalAdcLoadCalibrationValue(); result = adc_sum/size; if((adc_cal_postive!=0xfff)&&(adc_cal_negtive!=0xfff)){ int delta = ((int)(adc_cal_postive-adc_cal_negtive))>>1; if(ch&0x01) { result = ((result-delta)*1000 /(adc_cal_postive+adc_cal_negtive)); } else { result = ((result+delta)*1000 /(adc_cal_postive+adc_cal_negtive)); } } else { result = ((result*1000) >>12); } if(high_resol == TRUE) { result = result*8/10; } else { result = result*adc_Lambda[ch-2]*8/10000; } return result; }