220 lines
6.5 KiB
C
220 lines
6.5 KiB
C
/*
|
|
* 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 <rtthread.h>
|
|
#include <rtdevice.h>
|
|
#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
|
|
/*@}*/
|