/* * File : adc.c * This file is part of RT-Thread RTOS * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Change Logs: * Date Author Notes * 2017-09-18 Haley the first version */ #include #include #include "am_mcu_apollo.h" #ifdef RT_USING_ADC /* messagequeue define */ struct rt_messagequeue adcbat_mq; #define BATTERY_GPIO 35 /* Battery */ #define BATTERY_ADC_PIN AM_HAL_PIN_35_ADCSE7 #define BATTERY_ADC_CHANNEL AM_HAL_ADC_SLOT_CHSEL_SE7 /* BATTERY ADC采集通道 */ #define BATTERY_ADC_CHANNELNUM 7 /* BATTERY ADC采集通道号 */ #define ADC_CTIMER_NUM 3 /* ADC使用定时器 */ #define ADC_CTIMER_COUNT (2048/512 - 1) #define ADC_CHANNEL_NUM 1 /* ADC采集通道个数 */ #define ADC_SAMPLE_NUM 8 /* ADC采样个数 */ rt_uint8_t bat_adc_cnt = 0; static rt_uint8_t am_adcbat_buffer_pool[256]; static rt_int16_t am_adcbat_buffertemp[32]; rt_uint8_t am_adc_data_get(rt_uint8_t channel, rt_int16_t *buff, rt_uint16_t size) { rt_uint8_t adc_bufftemp[32]; if (channel == BATTERY_ADC_CHANNELNUM) { /* wait adc message forever */ rt_mq_recv(&adcbat_mq, adc_bufftemp, 32, RT_WAITING_FOREVER); } /* copy the data */ rt_memcpy(buff, adc_bufftemp, size*sizeof(rt_int16_t)); return 0; } void am_adc_start(rt_uint8_t channel) { /* messagequeue init */ rt_mq_init(&adcbat_mq, "mq_adcbat", &am_adcbat_buffer_pool[0], 32 - sizeof(void*), sizeof(am_adcbat_buffer_pool), RT_IPC_FLAG_FIFO); /* Start the ctimer */ am_hal_ctimer_start(ADC_CTIMER_NUM, AM_HAL_CTIMER_TIMERA); /* Trigger the ADC once */ am_hal_adc_trigger(); } void am_adc_stop(rt_uint8_t channel) { /* Stop the ctimer */ am_hal_ctimer_stop(ADC_CTIMER_NUM, AM_HAL_CTIMER_TIMERA); /* messagequeue delete */ rt_mq_delete(&adceeg_mq); /* messagequeue delete */ rt_mq_delete(&adcbat_mq); } /** * @brief Interrupt handler for the ADC * * This function is Interrupt handler for the ADC * * @return None. */ void am_adc_isr(void) { uint32_t ui32Status, ui32FifoData; /* enter interrupt */ rt_interrupt_enter(); /* Read the interrupt status */ ui32Status = am_hal_adc_int_status_get(true); /* Clear the ADC interrupt */ am_hal_adc_int_clear(ui32Status); /* If we got a FIFO 75% full (which should be our only ADC interrupt), go ahead and read the data */ if (ui32Status & AM_HAL_ADC_INT_FIFOOVR1) { do { /* Read the value from the FIFO into the circular buffer */ ui32FifoData = am_hal_adc_fifo_pop(); if (AM_HAL_ADC_FIFO_SLOT(ui32FifoData) == BATTERY_ADC_CHANNELNUM) { am_adcbat_buffertemp[bat_adc_cnt++] = AM_HAL_ADC_FIFO_SAMPLE(ui32FifoData); } if ((bat_adc_cnt > ADC_SAMPLE_NUM + 2 - 1)) { bat_adc_cnt = 0; /* send the message */ rt_mq_send(&adcbat_mq, am_adcbat_buffertemp, ADC_SAMPLE_NUM*sizeof(rt_int16_t)); } } while (AM_HAL_ADC_FIFO_COUNT(ui32FifoData) > 0); } /* leave interrupt */ rt_interrupt_leave(); } static void timerA3_for_adc_init(void) { /* Start a timer to trigger the ADC periodically (1 second) */ am_hal_ctimer_config_single(ADC_CTIMER_NUM, AM_HAL_CTIMER_TIMERA, AM_HAL_CTIMER_XT_2_048KHZ | AM_HAL_CTIMER_FN_REPEAT | AM_HAL_CTIMER_INT_ENABLE | AM_HAL_CTIMER_PIN_ENABLE); am_hal_ctimer_int_enable(AM_HAL_CTIMER_INT_TIMERA3); /* Set 512 sample rate */ am_hal_ctimer_period_set(ADC_CTIMER_NUM, AM_HAL_CTIMER_TIMERA, ADC_CTIMER_COUNT, 1); /* Enable the timer A3 to trigger the ADC directly */ am_hal_ctimer_adc_trigger_enable(); /* Start the timer */ //am_hal_ctimer_start(ADC_CTIMER_NUM, AM_HAL_CTIMER_TIMERA); } /** * @brief Initialize the ADC * * This function initialize the ADC * * @return None. */ int rt_hw_adc_init(void) { am_hal_adc_config_t sADCConfig; /* timer for adc init*/ timerA3_for_adc_init(); /* Set a pin to act as our ADC input */ am_hal_gpio_pin_config(BATTERY_GPIO, BATTERY_ADC_PIN); /* Enable interrupts */ am_hal_interrupt_enable(AM_HAL_INTERRUPT_ADC); /* Enable the ADC power domain */ am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_ADC); /* Set up the ADC configuration parameters. These settings are reasonable for accurate measurements at a low sample rate */ sADCConfig.ui32Clock = AM_HAL_ADC_CLOCK_HFRC; sADCConfig.ui32TriggerConfig = AM_HAL_ADC_TRIGGER_SOFT; sADCConfig.ui32Reference = AM_HAL_ADC_REF_INT_2P0; sADCConfig.ui32ClockMode = AM_HAL_ADC_CK_LOW_POWER; sADCConfig.ui32PowerMode = AM_HAL_ADC_LPMODE_0; sADCConfig.ui32Repeat = AM_HAL_ADC_REPEAT; am_hal_adc_config(&sADCConfig); /* For this example, the samples will be coming in slowly. This means we can afford to wake up for every conversion */ am_hal_adc_int_enable(AM_HAL_ADC_INT_FIFOOVR1); /* Set up an ADC slot */ am_hal_adc_slot_config(BATTERY_ADC_CHANNELNUM, AM_HAL_ADC_SLOT_AVG_1 | AM_HAL_ADC_SLOT_14BIT | BATTERY_ADC_CHANNEL | AM_HAL_ADC_SLOT_ENABLE); /* Enable the ADC */ am_hal_adc_enable(); /* Trigger the ADC once */ //am_hal_adc_trigger(); //rt_kprintf("adc_init!\n"); return 0; } #ifdef RT_USING_COMPONENTS_INIT INIT_BOARD_EXPORT(rt_hw_adc_init); #endif #endif /*@}*/