267 lines
7.3 KiB
C
267 lines
7.3 KiB
C
/***************************************************************************//**
|
|
* @file dev_accel.c
|
|
* @brief Accelerometer driver of RT-Thread RTOS for EFM32
|
|
* COPYRIGHT (C) 2011, RT-Thread Development Team
|
|
* @author onelife
|
|
* @version 0.4 beta
|
|
*******************************************************************************
|
|
* @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-07-13 onelife Initial creation for using EFM32 ADC module to
|
|
* interface the Freescale MMA7361L
|
|
******************************************************************************/
|
|
|
|
/***************************************************************************//**
|
|
* @addtogroup efm32
|
|
* @{
|
|
******************************************************************************/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "board.h"
|
|
#include "drv_adc.h"
|
|
#include "dev_accel.h"
|
|
|
|
#if defined(EFM32_USING_ACCEL)
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/* Private define ------------------------------------------------------------*/
|
|
/* Private macro -------------------------------------------------------------*/
|
|
#ifdef RT_ACCEL_DEBUG
|
|
#define accel_debug(format,args...) rt_kprintf(format, ##args)
|
|
#else
|
|
#define accel_debug(format,args...)
|
|
#endif
|
|
|
|
/* Private constants ---------------------------------------------------------*/
|
|
static rt_device_t accel;
|
|
static struct efm32_adc_control_t control = \
|
|
{ADC_MODE_SCAN, {3, ACCEL_USING_DMA}, {}};
|
|
static struct efm32_accel_result_t accelOffset = {0};
|
|
static rt_bool_t accelInTime = true;
|
|
|
|
/* Private variables ---------------------------------------------------------*/
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
/* Private functions ---------------------------------------------------------*/
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Get accelerometer output
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[out] data
|
|
* Pointer to output buffer
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
rt_err_t efm_accel_get_data(struct efm32_accel_result_t *data)
|
|
{
|
|
RT_ASSERT(accel != RT_NULL);
|
|
|
|
struct efm32_adc_result_t result;
|
|
|
|
if (data == RT_NULL)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
result.mode = control.mode;
|
|
result.buffer = (void *)data;
|
|
accel->control(accel, RT_DEVICE_CTRL_RESUME, &result);
|
|
accel->control(accel, RT_DEVICE_CTRL_ADC_RESULT, &result);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Accelerometer timeout interrupt handler
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] parameter
|
|
* Parameter
|
|
******************************************************************************/
|
|
static void efm_accel_timer(void* parameter)
|
|
{
|
|
accelInTime = false;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Accelerometer auto-zero calibration function
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] period
|
|
* Time period to perform auto-zero calibration
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
rt_err_t efm_accel_auto_zero(rt_tick_t period)
|
|
{
|
|
RT_ASSERT(accel != RT_NULL);
|
|
|
|
rt_timer_t calTimer;
|
|
struct efm32_accel_result_t min = {0x7ff, 0x7ff, 0x7ff};
|
|
struct efm32_accel_result_t max = {0x7ff, 0x7ff, 0x7ff};
|
|
struct efm32_accel_result_t temp;
|
|
struct efm32_adc_result_t result;
|
|
|
|
if ((calTimer = rt_timer_create(
|
|
"cal_tmr",
|
|
efm_accel_timer,
|
|
RT_NULL,
|
|
period,
|
|
RT_TIMER_FLAG_ONE_SHOT)) == RT_NULL)
|
|
{
|
|
accel_debug("Accel err: Create timer failed!\n");
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
result.mode = control.mode;
|
|
result.buffer = (void *)&temp;
|
|
accelInTime = true;
|
|
rt_timer_start(calTimer);
|
|
do
|
|
{
|
|
accel->control(accel, RT_DEVICE_CTRL_RESUME, &result);
|
|
accel->control(accel, RT_DEVICE_CTRL_ADC_RESULT, &result);
|
|
if (temp.x < min.x)
|
|
{
|
|
min.x = temp.x;
|
|
}
|
|
if (temp.y < min.y)
|
|
{
|
|
min.y = temp.y;
|
|
}
|
|
if (temp.z < min.z)
|
|
{
|
|
min.z = temp.z;
|
|
}
|
|
if (temp.x > max.x)
|
|
{
|
|
max.x = temp.x;
|
|
}
|
|
if (temp.y > max.y)
|
|
{
|
|
max.y = temp.y;
|
|
}
|
|
if (temp.z > max.z)
|
|
{
|
|
max.z = temp.z;
|
|
}
|
|
rt_thread_sleep(1);
|
|
} while (accelInTime);
|
|
|
|
accelOffset.x = (min.x + max.x) >> 1;
|
|
accelOffset.y = (min.y + max.y) >> 1;
|
|
accelOffset.z = (min.z + max.z) >> 1;
|
|
accel_debug("Accel: Min %x %x %x, max %x %x %x, Offset %x %x %x\n",
|
|
min.x, min.y, min.z, max.x, max.y, max.z,
|
|
accelOffset.x, accelOffset.y, accelOffset.z);
|
|
|
|
rt_timer_delete(calTimer);
|
|
return RT_EOK;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Initialize the accelerometer
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
rt_err_t efm_accel_init(void)
|
|
{
|
|
ADC_InitScan_TypeDef scanInit = ADC_INITSCAN_DEFAULT;
|
|
|
|
#if defined(EFM32_G290_DK)
|
|
/* Enable accelerometer */
|
|
DVK_enablePeripheral(DVK_ACCEL);
|
|
/* Select low g-range */
|
|
DVK_disablePeripheral(DVK_ACCEL_GSEL);
|
|
#endif
|
|
|
|
do
|
|
{
|
|
/* Find ADC device */
|
|
accel = rt_device_find(ACCEL_USING_DEVICE_NAME);
|
|
if (accel == RT_NULL)
|
|
{
|
|
accel_debug("Accel err: Can't find device: %s!\n", ACCEL_USING_DEVICE_NAME);
|
|
break;
|
|
}
|
|
accel_debug("Accel: Find device %s\n", ACCEL_USING_DEVICE_NAME);
|
|
|
|
/* Init ADC for scan mode */
|
|
scanInit.reference = adcRefVDD;
|
|
scanInit.input = ACCEL_X_ADC_CH | ACCEL_Y_ADC_CH | ACCEL_Z_ADC_CH;
|
|
|
|
control.scan.init = &scanInit;
|
|
accel->control(accel, RT_DEVICE_CTRL_ADC_MODE, &control);
|
|
|
|
accel_debug("Accel: Init OK\n");
|
|
return RT_EOK;
|
|
} while (0);
|
|
|
|
accel_debug("Accel err: Init failed!\n");
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* Export to FINSH
|
|
******************************************************************************/
|
|
#ifdef RT_USING_FINSH
|
|
#include <finsh.h>
|
|
|
|
void accel_cal(rt_uint32_t second)
|
|
{
|
|
efm_accel_auto_zero(RT_TICK_PER_SECOND * second);
|
|
|
|
rt_kprintf("Calibration done. Offset: 0x%03x, 0x%03x, 0x%03x\n",
|
|
accelOffset.x, accelOffset.y, accelOffset.z);
|
|
}
|
|
FINSH_FUNCTION_EXPORT(accel_cal, auto-zero calibration.)
|
|
|
|
void list_accel(void)
|
|
{
|
|
struct efm32_accel_result_t temp;
|
|
rt_int32_t x, y, z;
|
|
|
|
if ((accelOffset.x == 0) && \
|
|
(accelOffset.y == 0) && \
|
|
(accelOffset.z == 0))
|
|
{
|
|
rt_kprintf("Please calibrate the device first!\n");
|
|
return;
|
|
}
|
|
efm_accel_get_data(&temp);
|
|
x = temp.x - accelOffset.x;
|
|
y = temp.y - accelOffset.y;
|
|
z = temp.z - accelOffset.z;
|
|
|
|
rt_kprintf("X: %d, Y: %d, Z: %d\n", x, y, z);
|
|
}
|
|
FINSH_FUNCTION_EXPORT(list_accel, list accelerometer info.)
|
|
#endif
|
|
|
|
#endif
|
|
/***************************************************************************//**
|
|
* @}
|
|
******************************************************************************/
|