Mouse code for the MacroRat

Dependencies:   ITG3200 QEI

Revision:
18:6a4db94011d3
diff -r f713758f6238 -r 6a4db94011d3 mbed-dev/targets/TARGET_Atmel/TARGET_SAM_CortexM4/drivers/adc/adc2.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-dev/targets/TARGET_Atmel/TARGET_SAM_CortexM4/drivers/adc/adc2.c	Sun May 14 23:18:57 2017 +0000
@@ -0,0 +1,518 @@
+/**
+ * \file
+ *
+ * \brief ADC Controller driver.
+ *
+ * Copyright (c) 2013-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ *    Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#include "adc2.h"
+#include "sleepmgr.h"
+#include "status_codes.h"
+#include "sysclk.h"
+#include "pmc.h"
+
+/**
+ * \defgroup sam_drivers_adc2_group Analog-to-Digital Controller
+ *
+ * See \ref sam_adc2_quickstart.
+ *
+ * Driver for the Analog-to-Digital Controller. This driver provides access to
+ * the main features of the ADC controller.
+ *
+ * @{
+ */
+
+/* The number of channel in channel sequence1 register */
+#define ADC_SEQ1_CHANNEL_NUM                (8UL)
+
+/* The number of ADC interrupt source */
+#define ADC_NUM_OF_INTERRUPT_SOURCE         (24UL)
+
+
+const uint32_t adc_interrupt_mask[ADC_NUM_OF_INTERRUPT_SOURCE] = {
+    ADC_ISR_EOC0, ADC_ISR_EOC1, ADC_ISR_EOC2, ADC_ISR_EOC3,
+    ADC_ISR_EOC4, ADC_ISR_EOC5, ADC_ISR_EOC6, ADC_ISR_EOC7,
+#if (SAM4N)
+    ADC_ISR_EOC8, ADC_ISR_EOC9, ADC_ISR_EOC10, ADC_ISR_EOC11,
+    ADC_ISR_EOC12, ADC_ISR_EOC13, ADC_ISR_EOC14, ADC_ISR_EOC15,
+    ADC_ISR_EOC16,
+#endif
+#ifdef TEMP_SENSOR
+    ADC_ISR_TEMPCHG,
+#endif
+    ADC_ISR_EOCAL, ADC_ISR_DRDY,
+    ADC_ISR_GOVRE, ADC_ISR_COMPE, ADC_ISR_ENDRX, ADC_ISR_RXBUFF,
+};
+
+adc_callback_t adc_callback_pointer[ADC_NUM_OF_INTERRUPT_SOURCE];
+
+/**
+ * \brief Get the ADC default configurations.
+ *
+ * Use to initialize the configuration structure to known default values. This
+ * function should be called at the start of any ADC initiation.
+ *
+ * The default configuration is as follows:
+ * - 10-bit resolution
+ * - ADC clock frequency is 6MHz
+ * - Start Up Time is 64 periods ADC clock
+ * - Tracking Time is 3 periods of ADC clock
+ * - Transfer Period field shall be programmed with 2 as datasheet said
+ * - The controller converts channels in a simple numeric order
+ * - Appends the channel number to the conversion result in ADC_LCDR register
+ * - Only a Single Trigger is required to get an averaged value
+ *
+ * \param cfg Pointer to configuration structure to be initiated.
+ */
+void adc_get_config_defaults(struct adc_config *const cfg)
+{
+    /* Sanity check argument. */
+    Assert(cfg);
+
+#if SAMG55
+    cfg->resolution = ADC_12_BITS;
+#else
+    cfg->resolution = ADC_10_BITS;
+#endif
+    cfg->mck = sysclk_get_cpu_hz();
+    cfg->adc_clock = 6000000UL;
+    cfg->startup_time = ADC_STARTUP_TIME_4;
+    cfg->tracktim = 2;
+    cfg->transfer = 2;
+    cfg->useq = false;
+    cfg->tag = false;
+    cfg->aste = false;
+}
+
+/**
+ * \internal
+ * \brief Configure the ADC Module.
+ *
+ * \param adc  Base address of the ADC
+ * \param config   Configuration for the ADC
+ */
+static void adc_set_config(Adc *const adc, struct adc_config *config)
+{
+    uint32_t reg = 0;
+
+    reg =  (config->useq ? ADC_MR_USEQ_REG_ORDER : 0) |
+           ADC_MR_PRESCAL(config->mck /
+                          (2 * config->adc_clock) - 1) |
+           ADC_MR_TRACKTIM(config->tracktim) |
+           ADC_MR_TRANSFER(config->transfer) |
+           (config->startup_time);
+
+    adc->ADC_MR = reg;
+
+    adc->ADC_EMR = (config->tag ? ADC_EMR_TAG : 0) |
+                   (config->aste ? ADC_EMR_ASTE_SINGLE_TRIG_AVERAGE : 0);
+
+    adc_set_resolution(adc, config->resolution);
+}
+
+#ifdef TEMP_SENSOR
+/**
+ * \brief Get the ADC Temperature Sensor default configurations.
+ *
+ * Use to initialize the configuration structure to known default values.
+ *
+ * The default configuration is as follows:
+ * - Generates an event when the converted data is in the comparison window
+ * - The window range is 0xFF ~ 0xFFF
+ *
+ * \param cfg Pointer to temperature sensor configuration structure
+ *        to be initiated.
+ */
+void adc_temp_sensor_get_config_defaults(
+    struct adc_temp_sensor_config *const cfg)
+{
+    /*Sanity check argument. */
+    Assert(cfg);
+
+    cfg->tempon = true;
+    cfg->mode = ADC_TEMP_CMP_MODE_2;
+    cfg->low_threshold = 0xFF;
+    cfg->high_threshold = 0xFFF;
+}
+
+/**
+ * \brief Configure the ADC temperature sensor.
+ *
+ * \param adc  Base address of the ADC
+ * \param config   Configuration for the ADC temperature sensor
+ */
+void adc_temp_sensor_set_config(Adc *const adc,
+                                struct adc_temp_sensor_config *config)
+{
+    uint32_t reg = 0;
+
+    reg = ((config->tempon) ? ADC_TEMPMR_TEMPON : 0) | (config->mode);
+    adc->ADC_TEMPMR = reg;
+
+    adc->ADC_TEMPCWR = ADC_TEMPCWR_TLOWTHRES(config->low_threshold) |
+                       ADC_TEMPCWR_THIGHTHRES(config->high_threshold);
+}
+#endif
+
+#if (SAMG)
+/**
+ * \brief Get the Last Channel Specific Measurement default configurations.
+ *
+ * Use to initialize the configuration structure to known default values.
+ *
+ * The default configuration is as follows:
+ * - Generates an event when the converted data is in the comparison window
+ * - The window range is 0xFF ~ 0xFFF
+ *
+ * \param cfg Pointer to last channel configuration structure
+ *        to be initiated.
+ */
+void adc_last_channel_get_config_defaults(
+    struct adc_last_channel_config *const cfg)
+{
+    /*Sanity check argument. */
+    Assert(cfg);
+
+    cfg->dual_trig_on = true;
+    cfg->mode = ADC_LAST_CHANNEL_CMP_MODE_2;
+    cfg->low_threshold = 0xFF;
+    cfg->high_threshold = 0xFFF;
+}
+
+/**
+ * \brief Configure the ADC Last Channel Specific Measurement.
+ *
+ * \param adc  Base address of the ADC
+ * \param config   Configuration for the last channel
+ */
+void adc_last_channel_set_config(Adc *const adc,
+                                 struct adc_last_channel_config *config)
+{
+    uint32_t reg = 0;
+
+    reg = ((config->dual_trig_on) ? ADC_LCTMR_DUALTRIG : 0) | (config->mode);
+    adc->ADC_LCTMR = reg;
+
+    adc->ADC_LCCWR = ADC_LCCWR_LOWTHRES(config->low_threshold) |
+                     ADC_LCCWR_HIGHTHRES(config->high_threshold);
+}
+#endif
+
+/**
+ * \brief Initialize the ADC Module.
+ *
+ * \param adc  Base address of the ADC
+ * \param config   Configuration for the ADC
+ *
+ * \retval STATUS_OK  Initialization is finished.
+ * \retval STATUS_ERR_BUSY  Initialization failed.
+ */
+enum status_code adc_init(Adc *const adc, struct adc_config *config)
+{
+    Assert(adc);
+    Assert(config);
+
+    if ((adc_get_interrupt_status(adc) & ADC_ISR_DRDY) == ADC_ISR_DRDY) {
+        return STATUS_ERR_BUSY;
+    }
+
+    /* Reset and configure the ADC module */
+    adc->ADC_CR = ADC_CR_SWRST;
+    adc_set_config(adc, config);
+
+    uint32_t i;
+    for (i = 0; i < ADC_NUM_OF_INTERRUPT_SOURCE; i++) {
+        adc_callback_pointer[i] = 0;
+    }
+
+    return STATUS_OK;
+}
+
+/**
+ * \brief Configure conversion resolution.
+ *
+ * \param adc  Base address of the ADC.
+ * \param res Conversion resolution.
+ *
+ */
+void adc_set_resolution(Adc *const adc,
+                        const enum adc_resolution res)
+{
+#if SAMG55
+    adc->ADC_EMR |= res;
+#else
+    if (res == ADC_11_BITS || res == ADC_12_BITS) {
+        adc->ADC_MR &= ~ADC_MR_LOWRES;
+        adc->ADC_EMR |= res;
+    } else {
+        adc->ADC_MR |= res;
+        adc->ADC_EMR &= ~ADC_EMR_OSR_Msk;
+    }
+#endif
+}
+
+/**
+ * \brief Configure comparison mode.
+ *
+ * \param adc  Base address of the ADC.
+ * \param mode Comparison mode.
+ * \param channel Comparison Selected Channel.
+ * \param cmp_filter Compare Event Filtering.
+ */
+void adc_set_comparison_mode(Adc *const adc,
+                             const enum adc_cmp_mode mode,
+                             const enum adc_channel_num channel, uint8_t cmp_filter)
+{
+    if (channel != ADC_CHANNEL_ALL) {
+        adc_ch_sanity_check(adc, channel);
+    }
+
+    uint32_t reg;
+
+    reg = adc->ADC_EMR;
+
+    reg &= ~(ADC_EMR_CMPSEL_Msk |
+             ADC_EMR_CMPMODE_Msk |
+             ADC_EMR_CMPFILTER_Msk);
+    reg |= mode |
+           ((channel == ADC_CHANNEL_ALL) ? ADC_EMR_CMPALL
+            : ADC_EMR_CMPSEL(channel)) |
+           ADC_EMR_CMPFILTER(cmp_filter);
+
+    adc->ADC_EMR = reg;
+}
+
+/**
+ * \brief Configure ADC power mode.
+ *
+ * \param adc  Base address of the ADC.
+ * \param mode   ADC power mode value.
+ */
+void adc_set_power_mode(Adc *const adc,
+                        const enum adc_power_mode mode)
+{
+    uint32_t reg;
+
+    reg = adc->ADC_MR;
+
+    switch (mode) {
+        case ADC_POWER_MODE_0:
+            reg |= ADC_MR_SLEEP_NORMAL;
+            break;
+
+        case ADC_POWER_MODE_1:
+            reg |= ADC_MR_SLEEP_SLEEP;
+            break;
+    }
+
+    adc->ADC_MR = reg;
+}
+
+/**
+ * \brief Set callback for ADC
+ *
+ * \param adc  Base address of the ADC
+ * \param source    Interrupt source
+ * \param callback  Callback function pointer
+ * \param irq_level Interrupt level
+ */
+void adc_set_callback(Adc *const adc, enum adc_interrupt_source source,
+                      adc_callback_t callback, uint8_t irq_level)
+{
+    Assert(adc);
+    Assert(callback);
+
+    adc_callback_pointer[source] = callback;
+    irq_register_handler(ADC_IRQn, irq_level);
+
+    /* Enable the specified interrupt source */
+    adc_enable_interrupt(adc, source);
+}
+
+/**
+ * \brief Enable ADC interrupts.
+ *
+ * \param adc  Base address of the ADC.
+ * \param interrupt_source Interrupts to be enabled.
+ */
+void adc_enable_interrupt(Adc *const adc,
+                          enum adc_interrupt_source interrupt_source)
+{
+    if (interrupt_source == ADC_INTERRUPT_ALL) {
+        adc->ADC_IER = ADC_INTERRUPT_ALL;
+        return;
+    } else {
+        adc->ADC_IER = adc_interrupt_mask[interrupt_source];
+    }
+}
+
+/**
+ * \brief Disable ADC interrupts.
+ *
+ * \param adc  Base address of the ADC.
+ * \param interrupt_source Interrupts to be disabled.
+ */
+void adc_disable_interrupt(Adc *const adc,
+                           enum adc_interrupt_source interrupt_source)
+{
+    if (interrupt_source == ADC_INTERRUPT_ALL) {
+        adc->ADC_IDR = ADC_INTERRUPT_ALL;
+        return;
+    } else {
+        adc->ADC_IDR = adc_interrupt_mask[interrupt_source];
+    }
+}
+
+/**
+ * \internal
+ * \brief Common ADC interrupt handler
+ *
+ * The optional callback used by the interrupt handler is set by the
+ * adc_set_callback() function.
+ *
+ * \param inst_num ADC instance number to handle interrupt for
+ * \param source   Interrupt source number
+ */
+static void adc_interrupt(enum adc_interrupt_source source)
+{
+    if (adc_callback_pointer[source]) {
+        adc_callback_pointer[source]();
+    }
+}
+
+/**
+ * \internal
+ * \brief Call the callback function if the corresponding interrupt is asserted
+ *
+ * \param adc  Base address of the ADC.
+ */
+static void adc_process_callback(Adc *const adc)
+{
+    volatile uint32_t status;
+    uint32_t cnt;
+
+    status = adc_get_interrupt_status(adc);
+
+    for (cnt = 0; cnt < ADC_NUM_OF_INTERRUPT_SOURCE; cnt++) {
+        if (status & adc_interrupt_mask[cnt]) {
+            adc_interrupt((enum adc_interrupt_source)cnt);
+        }
+    }
+}
+
+/**
+ * \brief Interrupt handler for ADC.
+ */
+void ADC_Handler(void)
+{
+    adc_process_callback(ADC);
+}
+
+/**
+ * \brief Enable ADC Module.
+ *
+ */
+void adc_enable(void)
+{
+    /* Enable peripheral clock. */
+    pmc_enable_periph_clk(ID_ADC);
+    sleepmgr_lock_mode(SLEEP_MODE_ADC);
+}
+
+/**
+ * \brief Disable ADC Module.
+ *
+ */
+void adc_disable(void)
+{
+    /* Disable peripheral clock. */
+    pmc_disable_periph_clk(ID_ADC);
+    sleepmgr_unlock_mode(SLEEP_MODE_ADC);
+}
+
+/**
+ * \brief Configure conversion sequence.
+ *
+ * \param adc  Base address of the ADC.
+ * \param ch_list Channel sequence list.
+ * \param uc_num Number of channels in the list.
+ */
+void adc_configure_sequence(Adc *const adc,
+                            const enum adc_channel_num ch_list[], uint8_t uc_num)
+{
+    uint8_t uc_counter;
+
+    /* Set user sequence mode */
+    adc->ADC_MR |= ADC_MR_USEQ_REG_ORDER;
+#if (SAM4N)
+    adc->ADC_SEQR1 = 0;
+    adc->ADC_SEQR2 = 0;
+#endif
+#if (SAMG)
+    adc->ADC_SEQR1 = 0;
+#endif
+
+    if (uc_num <= ADC_SEQ1_CHANNEL_NUM) {
+        for (uc_counter = 0; uc_counter < uc_num; uc_counter++) {
+#if (SAM4N || SAMG)
+            adc->ADC_SEQR1
+#endif
+            |= ch_list[uc_counter] << (4 * uc_counter);
+        }
+    } else {
+        for (uc_counter = 0; uc_counter <= ADC_SEQ1_CHANNEL_NUM;
+                uc_counter++) {
+#if (SAM4N || SAMG)
+            adc->ADC_SEQR1
+#endif
+            |= ch_list[uc_counter] << (4 * uc_counter);
+        }
+        for (uc_counter = 0; uc_counter < uc_num - ADC_SEQ1_CHANNEL_NUM;
+                uc_counter++) {
+#if (SAM4N)
+            adc->ADC_SEQR2 |= ch_list[8 + uc_counter] << (4 * uc_counter);
+#endif
+        }
+    }
+}
+
+//@}