mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2025-01-15 07:39:33 +08:00
ea6d73f140
1. Upgrade Cortex driver library (CMSIS -> CMSIS & Device): version 2.3.2 -> 3.0.1 & 3.0.0 - Remove "bsp/efm32/Libraries/CMSIS/Lib/ARM", "bsp/efm32/Libraries/CMSIS/Lib/G++" and "bsp/efm32/Libraries/CMSIS/SVD" to save space 2. Upgrade EFM32 driver libraries (efm32lib -> emlib): version 2.3.2 -> 3.0.0 - Remove "bsp/efm32/Libraries/Device/EnergyMicro/EFM32LG" and "bsp/efm32/Libraries/Device/EnergyMicro/EFM32TG" to save space 3. Upgrade EFM32GG_DK3750 development kit driver library: version 1.2.2 -> 2.0.1 4. Upgrade EFM32_Gxxx_DK development kit driver library: version 1.7.3 -> 2.0.1 5. Add energy management unit driver and test code 6. Modify linker script and related code to compatible with new version of libraries 7. Change EFM32 branch version number to 1.0 8. Add photo frame demo application git-svn-id: https://rt-thread.googlecode.com/svn/trunk@2122 bbd45198-f89e-11dd-88c7-29a3b14d5316
422 lines
10 KiB
C
422 lines
10 KiB
C
/***************************************************************************//**
|
|
* @file drv_acmp.c
|
|
* @brief ACMP (analog comparator) driver of RT-Thread RTOS for EFM32
|
|
* COPYRIGHT (C) 2012, RT-Thread Development Team
|
|
* @author onelife
|
|
* @version 1.0
|
|
*******************************************************************************
|
|
* @section License
|
|
* The license and distribution terms for this file may be found in the file
|
|
* LICENSE in this distribution or at http://www.rt-thread.org/license/LICENSE
|
|
*******************************************************************************
|
|
* @section Change Logs
|
|
* Date Author Notes
|
|
* 2011-02-21 onelife Initial creation for EFM32
|
|
* 2011-06-17 onelife Modify init and control function for efm32lib v2
|
|
* upgrading
|
|
******************************************************************************/
|
|
|
|
/***************************************************************************//**
|
|
* @addtogroup efm32
|
|
* @{
|
|
******************************************************************************/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "board.h"
|
|
#include "drv_acmp.h"
|
|
|
|
#if (defined(RT_USING_ACMP0) || defined(RT_USING_ACMP1))
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/* Private define ------------------------------------------------------------*/
|
|
/* Private macro -------------------------------------------------------------*/
|
|
#ifdef RT_ACMP_DEBUG
|
|
#define acmp_debug(format,args...) rt_kprintf(format, ##args)
|
|
#else
|
|
#define acmp_debug(format,args...)
|
|
#endif
|
|
|
|
/* Private variables ---------------------------------------------------------*/
|
|
#ifdef RT_USING_ACMP0
|
|
static struct rt_device acmp0_device;
|
|
#endif
|
|
|
|
#ifdef RT_USING_ACMP1
|
|
static struct rt_device acmp1_device;
|
|
#endif
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
ACMP_WarmTime_TypeDef efm32_acmp_WarmTimeCalc(rt_uint32_t hfperFreq);
|
|
|
|
/* Private functions ---------------------------------------------------------*/
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Initialize ACMP device
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] dev
|
|
* Pointer to device descriptor
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
static rt_err_t rt_acmp_init(rt_device_t dev)
|
|
{
|
|
RT_ASSERT(dev != RT_NULL);
|
|
|
|
struct efm32_acmp_device_t *acmp;
|
|
|
|
acmp = (struct efm32_acmp_device_t *)(dev->user_data);
|
|
|
|
acmp->hook.cbFunc = RT_NULL;
|
|
acmp->hook.userPtr = RT_NULL;
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Configure ACMP device
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] dev
|
|
* Pointer to device descriptor
|
|
*
|
|
* @param[in] cmd
|
|
* ACMP control command
|
|
*
|
|
* @param[in] args
|
|
* Arguments
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
static rt_err_t rt_acmp_control(
|
|
rt_device_t dev,
|
|
rt_uint8_t cmd,
|
|
void *args)
|
|
{
|
|
RT_ASSERT(dev != RT_NULL);
|
|
|
|
struct efm32_acmp_device_t *acmp;
|
|
|
|
acmp = (struct efm32_acmp_device_t *)(dev->user_data);
|
|
|
|
switch (cmd)
|
|
{
|
|
case RT_DEVICE_CTRL_SUSPEND:
|
|
/* Suspend device */
|
|
dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
|
|
ACMP_Disable(acmp->acmp_device);
|
|
break;
|
|
|
|
case RT_DEVICE_CTRL_RESUME:
|
|
/* Resume device */
|
|
dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
|
|
ACMP_Enable(acmp->acmp_device);
|
|
break;
|
|
|
|
case RT_DEVICE_CTRL_ACMP_INIT:
|
|
{
|
|
rt_bool_t int_en = false;
|
|
struct efm32_acmp_control_t *control;
|
|
|
|
control = (struct efm32_acmp_control_t *)args;
|
|
acmp_debug("ACMP: control -> init start\n");
|
|
|
|
/* Configure ACMPn */
|
|
if (control->init == RT_NULL)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
ACMP_Init(acmp->acmp_device, control->init);
|
|
ACMP_ChannelSet(acmp->acmp_device, control->negInput, control->posInput);
|
|
if (control->output != RT_NULL)
|
|
{
|
|
ACMP_GPIOSetup(
|
|
acmp->acmp_device,
|
|
control->output->location,
|
|
control->output->enable,
|
|
control->output->invert);
|
|
int_en = true;
|
|
}
|
|
if (control->hook.cbFunc != RT_NULL)
|
|
{
|
|
acmp->hook.cbFunc = control->hook.cbFunc;
|
|
acmp->hook.userPtr = control->hook.userPtr;
|
|
int_en = true;
|
|
}
|
|
|
|
if (int_en)
|
|
{
|
|
/* Enable edge interrupt */
|
|
ACMP_IntEnable(acmp->acmp_device, ACMP_IEN_EDGE);
|
|
ACMP_IntClear(acmp->acmp_device, ACMP_IFC_EDGE);
|
|
|
|
/* Enable ACMP0/1 interrupt vector in NVIC */
|
|
NVIC_ClearPendingIRQ(ACMP0_IRQn);
|
|
NVIC_SetPriority(ACMP0_IRQn, EFM32_IRQ_PRI_DEFAULT);
|
|
NVIC_EnableIRQ(ACMP0_IRQn);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case RT_DEVICE_CTRL_ACMP_OUTPUT:
|
|
*((rt_bool_t *)args) = \
|
|
(acmp->acmp_device->STATUS & ACMP_STATUS_ACMPOUT) ? true : false;
|
|
break;
|
|
|
|
default:
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Register ACMP device
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] device
|
|
* Pointer to device descriptor
|
|
*
|
|
* @param[in] name
|
|
* Device name
|
|
*
|
|
* @param[in] flag
|
|
* Configuration flags
|
|
*
|
|
* @param[in] acmp
|
|
* Pointer to ACMP device descriptor
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
rt_err_t rt_hw_acmp_register(
|
|
rt_device_t device,
|
|
const char *name,
|
|
rt_uint32_t flag,
|
|
struct efm32_acmp_device_t *acmp)
|
|
{
|
|
RT_ASSERT(device != RT_NULL);
|
|
|
|
device->type = RT_Device_Class_Char; /* fixme: should be acmp type */
|
|
device->rx_indicate = RT_NULL;
|
|
device->tx_complete = RT_NULL;
|
|
device->init = rt_acmp_init;
|
|
device->open = RT_NULL;
|
|
device->close = RT_NULL;
|
|
device->read = RT_NULL;
|
|
device->write = RT_NULL;
|
|
device->control = rt_acmp_control;
|
|
device->user_data = acmp;
|
|
|
|
/* register a character device */
|
|
return rt_device_register(device, name, flag);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* ACMP edge trigger interrupt handler
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
******************************************************************************/
|
|
void rt_hw_acmp_isr(rt_device_t dev)
|
|
{
|
|
RT_ASSERT(dev != RT_NULL);
|
|
|
|
struct efm32_acmp_device_t *acmp;
|
|
|
|
acmp = (struct efm32_acmp_device_t *)(dev->user_data);
|
|
|
|
if (acmp->hook.cbFunc != RT_NULL)
|
|
{
|
|
(acmp->hook.cbFunc)(acmp->hook.userPtr);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Initialize the specified ACMP unit
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] device
|
|
* Pointer to device descriptor
|
|
*
|
|
* @param[in] unitNumber
|
|
* Unit number
|
|
*
|
|
* @return
|
|
* Pointer to ACMP device
|
|
******************************************************************************/
|
|
static struct efm32_acmp_device_t *rt_hw_acmp_unit_init(
|
|
rt_device_t device,
|
|
rt_uint8_t unitNumber)
|
|
{
|
|
struct efm32_acmp_device_t *acmp;
|
|
efm32_irq_hook_init_t hook;
|
|
CMU_Clock_TypeDef acmpClock;
|
|
|
|
do
|
|
{
|
|
/* Allocate device */
|
|
acmp = rt_malloc(sizeof(struct efm32_acmp_device_t));
|
|
if (acmp == RT_NULL)
|
|
{
|
|
acmp_debug("ACMP err: no mem for ACMP%d\n", unitNumber);
|
|
break;
|
|
}
|
|
|
|
/* Initialization */
|
|
if (unitNumber >= ACMP_COUNT)
|
|
{
|
|
break;
|
|
}
|
|
switch (unitNumber)
|
|
{
|
|
case 0:
|
|
acmp->acmp_device = ACMP0;
|
|
acmpClock = (CMU_Clock_TypeDef)cmuClock_ACMP0;
|
|
break;
|
|
|
|
case 1:
|
|
acmp->acmp_device = ACMP1;
|
|
acmpClock = (CMU_Clock_TypeDef)cmuClock_ACMP1;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Enable ACMP clock */
|
|
CMU_ClockEnable(acmpClock, true);
|
|
|
|
/* Reset */
|
|
ACMP_Reset(acmp->acmp_device);
|
|
|
|
/* Config interrupt and NVIC */
|
|
hook.type = efm32_irq_type_acmp;
|
|
hook.unit = unitNumber;
|
|
hook.cbFunc = rt_hw_acmp_isr;
|
|
hook.userPtr = device;
|
|
efm32_irq_hook_register(&hook);
|
|
|
|
return acmp;
|
|
} while(0);
|
|
|
|
if (acmp)
|
|
{
|
|
rt_free(acmp);
|
|
}
|
|
rt_kprintf("ACMP: Init failed!\n");
|
|
return RT_NULL;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Initialize all ACMP module related hardware and register ACMP device to
|
|
* kernel
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
******************************************************************************/
|
|
void rt_hw_acmp_init(void)
|
|
{
|
|
struct efm32_acmp_device_t *acmp;
|
|
|
|
#ifdef RT_USING_ACMP0
|
|
if ((acmp = rt_hw_acmp_unit_init(&acmp0_device, 0)) != RT_NULL)
|
|
{
|
|
rt_hw_acmp_register(&acmp0_device, RT_ACMP0_NAME, EFM32_NO_DATA, acmp);
|
|
}
|
|
#endif
|
|
|
|
#ifdef RT_USING_ACMP1
|
|
if ((acmp = rt_hw_acmp_unit_init(&acmp1_device, 1)) != RT_NULL)
|
|
{
|
|
rt_hw_acmp_register(&acmp1_device, RT_ACMP1_NAME, EFM32_NO_DATA, acmp);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Calculate the warm-up time value providing at least 10us
|
|
*
|
|
* @param[in] hfperFreq
|
|
* Frequency in Hz of reference HFPER clock. Set to 0 to use currently defined
|
|
* HFPER clock setting
|
|
*
|
|
* @return
|
|
* Warm-up time value to use for ACMP in order to achieve at least 10us
|
|
******************************************************************************/
|
|
ACMP_WarmTime_TypeDef efm32_acmp_WarmTimeCalc(rt_uint32_t hfperFreq)
|
|
{
|
|
if (!hfperFreq)
|
|
{
|
|
hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER);
|
|
|
|
/* Just in case, make sure we get non-zero freq for below calculation */
|
|
if (!hfperFreq)
|
|
{
|
|
hfperFreq = 1;
|
|
}
|
|
}
|
|
|
|
/* Determine number of HFPERCLK cycle >= 10us */
|
|
if (4 * 1000000 / hfperFreq > 10)
|
|
{
|
|
return acmpWarmTime4;
|
|
}
|
|
else if (8 * 1000000 / hfperFreq > 10)
|
|
{
|
|
return acmpWarmTime8;
|
|
}
|
|
else if (16 * 1000000 / hfperFreq > 10)
|
|
{
|
|
return acmpWarmTime16;
|
|
}
|
|
else if (32 * 1000000 / hfperFreq > 10)
|
|
{
|
|
return acmpWarmTime32;
|
|
}
|
|
else if (64 * 1000000 / hfperFreq > 10)
|
|
{
|
|
return acmpWarmTime64;
|
|
}
|
|
else if (128 * 1000000 / hfperFreq > 10)
|
|
{
|
|
return acmpWarmTime128;
|
|
}
|
|
else if (256 * 1000000 / hfperFreq > 10)
|
|
{
|
|
return acmpWarmTime256;
|
|
}
|
|
else if (512 * 1000000 / hfperFreq > 10)
|
|
{
|
|
return acmpWarmTime512;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
/***************************************************************************//**
|
|
* @}
|
|
******************************************************************************/
|