123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690 |
- /**
- * @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 <string.h>
- #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<FILTER_SIZE;count++)
- {
- value_buf[count ++]= (uint16_t)(read_reg(ADC_CH_BASE + (ch * 0x80) + ((base + offset)<<2))&0xfff);
- value_buf[count] = (uint16_t)((read_reg(ADC_CH_BASE + (ch * 0x80) + ((base + offset)<<2))>>16)&0xfff);
- offset ++;
- }
- max = value_buf[0];
- min = value_buf[0];
- sum = value_buf[0];
- for(j=1;j<FILTER_SIZE;j++)
- {
- max = (max > 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;
- }
|