adc.c 6.0 KB
Newer Older
L
lin 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
/*
 * 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采集通道 */
#define BATTERY_ADC_CHANNELNUM  1                         /* BATTERY ADC采集通道号 */

#define ADC_CTIMER_NUM          3                         /* ADC使用定时器 */

#define ADC_CHANNEL_NUM         1                         /* ADC采集通道个数 */
#define ADC_SAMPLE_NUM          8                         /* ADC采样个数, 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
/*@}*/