rt-thread-official/bsp/apollo2/board/adc.c

197 lines
6.0 KiB
C
Raw Normal View History

/*
* 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-12-04 Haley the first version
*/
#include <rtdevice.h>
#include "am_mcu_apollo.h"
#include "board.h"
#ifdef RT_USING_ADC
/* sem define */
rt_sem_t adcsem = RT_NULL;
#define BATTERY_GPIO 29 /* Battery */
#define BATTERY_ADC_PIN AM_HAL_PIN_29_ADCSE1
#define BATTERY_ADC_CHANNEL AM_HAL_ADC_SLOT_CHSEL_SE1 /* BATTERY ADC<44>ɼ<EFBFBD>ͨ<EFBFBD><CDA8> */
#define BATTERY_ADC_CHANNELNUM 1 /* BATTERY ADC<44>ɼ<EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD> */
#define ADC_CTIMER_NUM 3 /* ADCʹ<43>ö<EFBFBD>ʱ<EFBFBD><CAB1> */
#define ADC_CHANNEL_NUM 1 /* ADC<44>ɼ<EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
#define ADC_SAMPLE_NUM 8 /* ADC<44><43><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, NE_OF_OUTPUT */
rt_uint8_t bat_adc_cnt = (ADC_CHANNEL_NUM + 1)*ADC_SAMPLE_NUM;
rt_int16_t am_adc_buffer_pool[64];
rt_uint8_t am_adc_data_get(rt_int16_t *buff, rt_uint16_t size)
{
/* wait adc interrupt release sem forever */
rt_sem_take(adcsem, RT_WAITING_FOREVER);
/* copy the data */
rt_memcpy(buff, am_adc_buffer_pool, size*sizeof(rt_int16_t));
return 0;
}
void am_adc_start(void)
{
/* adcsem create */
adcsem = rt_sem_create("adcsem", 0, 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(void)
{
/* Stop the ctimer */
am_hal_ctimer_stop(ADC_CTIMER_NUM, AM_HAL_CTIMER_TIMERA);
/* adcsem delete */
rt_sem_delete(adcsem);
}
/**
* @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;
/* 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_adc_buffer_pool[bat_adc_cnt++] = AM_HAL_ADC_FIFO_SAMPLE(ui32FifoData);
if(bat_adc_cnt > (ADC_CHANNEL_NUM + 1)*ADC_SAMPLE_NUM - 1)
{
/* shift data */
rt_memmove(am_adc_buffer_pool, am_adc_buffer_pool + ADC_CHANNEL_NUM*ADC_SAMPLE_NUM, ADC_CHANNEL_NUM*ADC_SAMPLE_NUM*sizeof(rt_int16_t));
bat_adc_cnt = (ADC_CHANNEL_NUM + 1)*ADC_SAMPLE_NUM;
/* release adcsem */
rt_sem_release(adcsem);
}
} while (AM_HAL_ADC_FIFO_COUNT(ui32FifoData) > 0);
}
}
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, 3, 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();
rt_kprintf("adc_init!\n");
return 0;
}
#ifdef RT_USING_COMPONENTS_INIT
INIT_BOARD_EXPORT(rt_hw_adc_init);
#endif
#endif
/*@}*/