mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2025-01-15 06:59:22 +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
896 lines
22 KiB
C
896 lines
22 KiB
C
/***************************************************************************//**
|
|
* @file dev_accel.c
|
|
* @brief Accelerometer 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-07-13 onelife Initial creation for using EFM32 ADC module to
|
|
* interface the Freescale MMA7361L
|
|
* 2011-08-02 onelife Add digital interface support of using EFM32 IIC
|
|
* module for the Freescale MMA7455L
|
|
******************************************************************************/
|
|
|
|
/***************************************************************************//**
|
|
* @addtogroup efm32
|
|
* @{
|
|
******************************************************************************/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "board.h"
|
|
|
|
#if defined(EFM32_USING_ACCEL)
|
|
#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
|
|
#include "drv_adc.h"
|
|
#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
|
|
#include "drv_iic.h"
|
|
#include "hdl_interrupt.h"
|
|
#endif
|
|
#include "dev_accel.h"
|
|
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/* Private define ------------------------------------------------------------*/
|
|
/* Private macro -------------------------------------------------------------*/
|
|
#ifdef EFM32_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;
|
|
#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
|
|
static struct efm32_adc_control_t control = \
|
|
{ADC_MODE_SCAN, {3, ACCEL_USING_DMA}, {}};
|
|
static struct efm32_accel_result_t accelOffset = {0};
|
|
#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
|
|
static const struct efm32_iic_control_t control = \
|
|
{IIC_STATE_MASTER, 0x0000};
|
|
#endif
|
|
static rt_bool_t accelInTime = true;
|
|
static rt_uint32_t accelConfig = 0;
|
|
|
|
/* Private variables ---------------------------------------------------------*/
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
/* Private functions ---------------------------------------------------------*/
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Get accelerometer output
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[out] data
|
|
* Pointer to output buffer
|
|
*
|
|
* @param[in] lowResolution
|
|
* Resolution selection
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
rt_err_t efm_accel_get_data(struct efm32_accel_result_t *data,
|
|
rt_bool_t lowResolution)
|
|
{
|
|
RT_ASSERT(accel != RT_NULL);
|
|
|
|
rt_err_t ret;
|
|
|
|
if (data == RT_NULL)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
ret = RT_EOK;
|
|
do
|
|
{
|
|
/* --------- ADC interface --------- */
|
|
#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
|
|
struct efm32_adc_result_t result;
|
|
|
|
result.mode = control.mode;
|
|
result.buffer = (void *)data;
|
|
if ((ret = accel->control(accel, RT_DEVICE_CTRL_RESUME,
|
|
(void *)&result)) != RT_EOK)
|
|
{
|
|
break;
|
|
}
|
|
if ((ret = accel->control(accel, RT_DEVICE_CTRL_ADC_RESULT, \
|
|
(void *)&result)) != RT_EOK)
|
|
{
|
|
break;
|
|
}
|
|
|
|
data->x += accelOffset.x - 0x800;
|
|
data->y += accelOffset.y - 0x800;
|
|
data->z += accelOffset.z - 0x800;
|
|
if (lowResolution)
|
|
{
|
|
data->x >>= 4;
|
|
data->y >>= 4;
|
|
data->z >>= 4;
|
|
}
|
|
|
|
/* --------- IIC interface --------- */
|
|
#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
|
|
if (lowResolution || \
|
|
((accelConfig & ACCEL_MASK_RANGE) != MCTL_RANGE_8G))
|
|
{
|
|
rt_int8_t buf[3];
|
|
|
|
buf[0] = XOUT8;
|
|
if (accel->read(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, \
|
|
sizeof(buf)) == 0)
|
|
{
|
|
ret = -RT_ERROR;
|
|
break;
|
|
}
|
|
data->x = buf[0];
|
|
data->y = buf[1];
|
|
data->z = buf[2];
|
|
}
|
|
else
|
|
{
|
|
rt_uint8_t buf[6];
|
|
rt_uint16_t *temp = (rt_uint16_t *)&buf;
|
|
|
|
buf[0] = XOUTL;
|
|
if (accel->read(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, \
|
|
sizeof(buf)) == 0)
|
|
{
|
|
ret = -RT_ERROR;
|
|
break;
|
|
}
|
|
data->x = (*temp & 0x200) ? ((rt_uint32_t)*temp | ~0x3FF) : \
|
|
((rt_uint32_t)*temp & 0x3FF);
|
|
data->y = (*++temp & 0x200) ? ((rt_uint32_t)*temp | ~0x3FF) : \
|
|
((rt_uint32_t)*temp & 0x3FF);
|
|
data->z = (*++temp & 0x200) ? ((rt_uint32_t)*temp | ~0x3FF) : \
|
|
((rt_uint32_t)*temp & 0x3FF);
|
|
}
|
|
#endif
|
|
return RT_EOK;
|
|
} while (0);
|
|
|
|
accel_debug("Accel err: Get data failed!\n");
|
|
return ret;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Accelerometer timeout interrupt handler
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] parameter
|
|
* Parameter
|
|
******************************************************************************/
|
|
static void efm_accel_timer(void* parameter)
|
|
{
|
|
accelInTime = false;
|
|
}
|
|
|
|
#if (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Accelerometer level and pulse detection interrupts handler
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] device
|
|
* Pointer to device descriptor
|
|
******************************************************************************/
|
|
static void efm_accel_isr(rt_device_t device)
|
|
{
|
|
rt_uint8_t buf[2];
|
|
|
|
if ((accelConfig & ACCEL_MASK_MODE) != ACCEL_MODE_MEASUREMENT)
|
|
{
|
|
/* Read detection source */
|
|
buf[0] = DETSRC;
|
|
if (accel->read(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 1) != 1)
|
|
{
|
|
accel_debug("Accel: read error\n");
|
|
return;
|
|
}
|
|
accel_debug("Accel: DETSRC %x\n", buf[0]);
|
|
|
|
/* Reset the interrupt flags: Part 1 */
|
|
buf[0] = INTRST;
|
|
buf[1] = INTRST_INT_1 | INTRST_INT_2;
|
|
accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2);
|
|
|
|
/* Read status to waste some time */
|
|
buf[0] = STATUS;
|
|
if (accel->read(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 1) != 1)
|
|
{
|
|
accel_debug("Accel: read error\n");
|
|
return;
|
|
}
|
|
accel_debug("Accel: STATUS %x\n", buf[0]);
|
|
|
|
/* Reset the interrupt flags: Part 2 */
|
|
buf[0] = INTRST;
|
|
buf[1] = 0x00;
|
|
accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Accelerometer configuration function
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] config
|
|
* Configuration options
|
|
*
|
|
* @param[in] level_threshold
|
|
* Level detection threshold
|
|
*
|
|
* @param[in] pulse_threshold
|
|
* Pulse detection threshold
|
|
*
|
|
* @param[in] pulse_duration
|
|
* Time window for 1st pulse
|
|
*
|
|
* @param[in] pulse_latency
|
|
* Pulse latency Time
|
|
*
|
|
* @param[in] pulse_duration2
|
|
* Time window for 2nd pulse
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
rt_err_t efm_accel_config(rt_uint32_t config,
|
|
rt_uint8_t level_threshold,
|
|
rt_uint8_t pulse_threshold,
|
|
rt_uint8_t pulse_duration,
|
|
rt_uint8_t pulse_latency,
|
|
rt_uint8_t pulse_duration2)
|
|
{
|
|
rt_err_t ret;
|
|
rt_uint8_t buf[2];
|
|
rt_uint8_t mode, mctl_reg, ctl1_reg, ctl2_reg;
|
|
|
|
ret = RT_EOK;
|
|
mctl_reg = 0;
|
|
ctl1_reg = 0;
|
|
ctl2_reg = 0;
|
|
|
|
/* Modify MCTL */
|
|
mode = config & ACCEL_MASK_MODE;
|
|
switch (mode)
|
|
{
|
|
case ACCEL_MODE_STANDBY:
|
|
mctl_reg |= MCTL_MODE_STANDBY;
|
|
break;
|
|
case ACCEL_MODE_MEASUREMENT:
|
|
mctl_reg |= MCTL_MODE_MEASUREMENT;
|
|
break;
|
|
case ACCEL_MODE_LEVEL:
|
|
mctl_reg |= MCTL_MODE_LEVEL;
|
|
break;
|
|
case ACCEL_MODE_PULSE:
|
|
mctl_reg |= MCTL_MODE_PULSE;
|
|
break;
|
|
default:
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
switch (config & ACCEL_MASK_RANGE)
|
|
{
|
|
case ACCEL_RANGE_8G:
|
|
mctl_reg |= MCTL_RANGE_8G;
|
|
break;
|
|
case ACCEL_RANGE_4G:
|
|
mctl_reg |= MCTL_RANGE_4G;
|
|
break;
|
|
case ACCEL_RANGE_2G:
|
|
mctl_reg |= MCTL_RANGE_2G;
|
|
break;
|
|
default:
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
if ((mode == ACCEL_MODE_LEVEL) || (mode == ACCEL_MODE_PULSE))
|
|
{
|
|
mctl_reg |= MCTL_PIN_INT1;
|
|
}
|
|
|
|
/* Modify CTL1 */
|
|
if (config & ACCEL_INTPIN_INVERSE)
|
|
{
|
|
ctl1_reg |= CTL1_INTPIN_INVERSE;
|
|
}
|
|
|
|
switch (config & ACCEL_MASK_INT)
|
|
{
|
|
case ACCEL_INT_LEVEL_PULSE:
|
|
ctl1_reg |= CTL1_INT_LEVEL_PULSE;
|
|
break;
|
|
case ACCEL_INT_PULSE_LEVEL:
|
|
ctl1_reg |= CTL1_INT_PULSE_LEVEL;
|
|
break;
|
|
case ACCEL_INT_SINGLE_DOUBLE:
|
|
ctl1_reg |= CTL1_INT_SINGLE_DOUBLE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (config & ACCEL_MASK_DISABLE)
|
|
{
|
|
case ACCEL_DISABLE_X:
|
|
ctl1_reg |= CTL1_X_DISABLE;
|
|
break;
|
|
case ACCEL_DISABLE_Y:
|
|
ctl1_reg |= CTL1_Y_DISABLE;
|
|
break;
|
|
case ACCEL_DISABLE_Z:
|
|
ctl1_reg |= CTL1_Z_DISABLE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (config & ACCEL_THRESHOLD_INTEGER)
|
|
{
|
|
ctl1_reg |= CTL1_THRESHOLD_INTEGER;
|
|
}
|
|
|
|
if (config & ACCEL_BANDWIDTH_125HZ)
|
|
{
|
|
ctl1_reg |= CTL1_BANDWIDTH_125HZ;
|
|
}
|
|
|
|
/* Modify CTL2 */
|
|
if (config & ACCEL_LEVEL_AND)
|
|
{
|
|
ctl2_reg |= CTL2_LEVEL_AND;
|
|
}
|
|
if (config & ACCEL_PULSE_AND)
|
|
{
|
|
ctl2_reg |= CTL2_PULSE_AND;
|
|
}
|
|
if (config & ACCEL_DRIVE_STRONG)
|
|
{
|
|
ctl2_reg |= CTL2_DRIVE_STRONG;
|
|
}
|
|
|
|
do
|
|
{
|
|
/* Write registers */
|
|
buf[0] = MCTL;
|
|
buf[1] = mctl_reg;
|
|
if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
|
|
{
|
|
ret = -RT_ERROR;
|
|
break;
|
|
}
|
|
accel_debug("Accel: MCTL %x\n", mctl_reg);
|
|
|
|
buf[0] = CTL1;
|
|
buf[1] = ctl1_reg;
|
|
if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
|
|
{
|
|
ret = -RT_ERROR;
|
|
break;
|
|
}
|
|
accel_debug("Accel: CTL1 %x\n", ctl1_reg);
|
|
|
|
buf[0] = CTL2;
|
|
buf[1] = ctl2_reg;
|
|
if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
|
|
{
|
|
ret = -RT_ERROR;
|
|
break;
|
|
}
|
|
accel_debug("Accel: CTL2 %x\n", ctl2_reg);
|
|
accelConfig = config;
|
|
|
|
if (mode == ACCEL_MODE_PULSE)
|
|
{
|
|
buf[0] = PDTH;
|
|
buf[1] = pulse_threshold;
|
|
if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
|
|
{
|
|
ret = -RT_ERROR;
|
|
break;
|
|
}
|
|
accel_debug("Accel: PDTH %x\n", buf[1]);
|
|
|
|
buf[0] = PW;
|
|
buf[1] = pulse_duration;
|
|
if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
|
|
{
|
|
ret = -RT_ERROR;
|
|
break;
|
|
}
|
|
accel_debug("Accel: PW %x\n", buf[1]);
|
|
|
|
buf[0] = LT;
|
|
buf[1] = pulse_latency;
|
|
if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
|
|
{
|
|
ret = -RT_ERROR;
|
|
break;
|
|
}
|
|
accel_debug("Accel: LT %x\n", buf[1]);
|
|
|
|
buf[0] = TW;
|
|
buf[1] = pulse_duration2;
|
|
if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
|
|
{
|
|
ret = -RT_ERROR;
|
|
break;
|
|
}
|
|
accel_debug("Accel: TW %x\n", buf[1]);
|
|
}
|
|
|
|
if ((mode == ACCEL_MODE_LEVEL) || (mode == ACCEL_MODE_PULSE))
|
|
{
|
|
efm32_irq_hook_init_t hook;
|
|
|
|
/* Reset the interrupt flags: Part 1 */
|
|
buf[0] = INTRST;
|
|
buf[1] = INTRST_INT_1 | INTRST_INT_2;
|
|
if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
|
|
{
|
|
ret = -RT_ERROR;
|
|
break;
|
|
}
|
|
|
|
/* Set level detection threshold */
|
|
buf[0] = LDTH;
|
|
if (config & ACCEL_THRESHOLD_INTEGER)
|
|
{
|
|
buf[1] = level_threshold;
|
|
}
|
|
else
|
|
{
|
|
buf[1] = level_threshold & 0x7f;
|
|
}
|
|
if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
|
|
{
|
|
ret = -RT_ERROR;
|
|
break;
|
|
}
|
|
accel_debug("Accel: LDTH %x\n", buf[1]);
|
|
|
|
/* Config interrupt */
|
|
hook.type = efm32_irq_type_gpio;
|
|
hook.unit = ACCEL_INT1_PIN;
|
|
hook.cbFunc = efm_accel_isr;
|
|
hook.userPtr = RT_NULL;
|
|
efm32_irq_hook_register(&hook);
|
|
hook.unit = ACCEL_INT2_PIN;
|
|
efm32_irq_hook_register(&hook);
|
|
/* Clear pending interrupt */
|
|
BITBAND_Peripheral(&(GPIO->IFC), ACCEL_INT1_PIN, 0x1UL);
|
|
BITBAND_Peripheral(&(GPIO->IFC), ACCEL_INT2_PIN, 0x1UL);
|
|
/* Set raising edge interrupt and clear/enable it */
|
|
GPIO_IntConfig(
|
|
ACCEL_INT1_PORT,
|
|
ACCEL_INT1_PIN,
|
|
true,
|
|
false,
|
|
true);
|
|
GPIO_IntConfig(
|
|
ACCEL_INT2_PORT,
|
|
ACCEL_INT2_PIN,
|
|
true,
|
|
false,
|
|
true);
|
|
if (((rt_uint8_t)ACCEL_INT1_PORT % 2) || \
|
|
((rt_uint8_t)ACCEL_INT2_PORT % 2))
|
|
{
|
|
NVIC_ClearPendingIRQ(GPIO_ODD_IRQn);
|
|
NVIC_SetPriority(GPIO_ODD_IRQn, EFM32_IRQ_PRI_DEFAULT);
|
|
NVIC_EnableIRQ(GPIO_ODD_IRQn);
|
|
}
|
|
if (!((rt_uint8_t)ACCEL_INT1_PORT % 2) || \
|
|
!((rt_uint8_t)ACCEL_INT2_PORT % 2))
|
|
{
|
|
NVIC_ClearPendingIRQ(GPIO_EVEN_IRQn);
|
|
NVIC_SetPriority(GPIO_EVEN_IRQn, EFM32_IRQ_PRI_DEFAULT);
|
|
NVIC_EnableIRQ(GPIO_EVEN_IRQn);
|
|
}
|
|
|
|
/* Reset the interrupt flags: Part 2 */
|
|
buf[0] = INTRST;
|
|
buf[1] = 0x00;
|
|
if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
|
|
{
|
|
ret = -RT_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
} while (0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Accelerometer auto-zero calibration function
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] mode
|
|
* 0, simple mode (assuming the device is placed on flat surface)
|
|
* 1, interaction method
|
|
*
|
|
* @param[in] period
|
|
* Time period to perform auto-zero calibration
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
rt_err_t efm_accel_auto_zero(rt_uint8_t mode, rt_tick_t period)
|
|
{
|
|
RT_ASSERT(accel != RT_NULL);
|
|
|
|
rt_timer_t calTimer;
|
|
struct efm32_accel_result_t min = {0, 0, 0};
|
|
struct efm32_accel_result_t max = {0, 0, 0};
|
|
struct efm32_accel_result_t temp, sum;
|
|
rt_int32_t simpleOffset[] = ACCEL_CAL_1G_VALUE;
|
|
rt_uint8_t cmd[7] = {0};
|
|
rt_uint8_t i, j;
|
|
|
|
/* Reset offset */
|
|
#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
|
|
accelOffset.x = 0;
|
|
accelOffset.y = 0;
|
|
accelOffset.z = 0;
|
|
|
|
#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
|
|
cmd[0] = XOFFL;
|
|
if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, cmd, sizeof(cmd)) == 0)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif
|
|
|
|
if (mode == ACCEL_CAL_SIMPLE)
|
|
{
|
|
/* Simple mode */
|
|
for (j = 0; j < ACCEL_CAL_ROUND; j++)
|
|
{
|
|
sum.x = 0x0;
|
|
sum.y = 0x0;
|
|
sum.z = 0x0;
|
|
|
|
for (i = 0; i < ACCEL_CAL_SAMPLES; i++)
|
|
{
|
|
#if (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
|
|
/* Waiting for data ready */
|
|
while(!GPIO_PinInGet(ACCEL_INT1_PORT, ACCEL_INT1_PIN));
|
|
#endif
|
|
if (efm_accel_get_data(&temp, false) != RT_EOK)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
sum.x += temp.x;
|
|
sum.y += temp.y;
|
|
sum.z += temp.z;
|
|
}
|
|
|
|
#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
|
|
temp.x = sum.x / ACCEL_CAL_SAMPLES;
|
|
temp.y = sum.y / ACCEL_CAL_SAMPLES;
|
|
temp.z = sum.z / ACCEL_CAL_SAMPLES - simpleOffset[ACCEL_G_SELECT];
|
|
if ((temp.x == 0) && (temp.y == 0) && \
|
|
(temp.z == 0))
|
|
{
|
|
accel_debug("Accel: Offset %+d %+d %+d\n",
|
|
accelOffset.x, accelOffset.y, accelOffset.z);
|
|
break;
|
|
}
|
|
accelOffset.x -= temp.x;
|
|
accelOffset.y -= temp.y;
|
|
accelOffset.z -= temp.z;
|
|
|
|
#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
|
|
temp.x = sum.x / (ACCEL_CAL_SAMPLES >> 1);
|
|
temp.y = sum.y / (ACCEL_CAL_SAMPLES >> 1);
|
|
temp.z = sum.z / (ACCEL_CAL_SAMPLES >> 1) \
|
|
- (simpleOffset[ACCEL_G_SELECT] << 1);
|
|
if ((temp.x == 0) && (temp.y == 0) && \
|
|
(temp.z == 0))
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* Set offset drift registers */
|
|
max.x -= temp.x;
|
|
max.y -= temp.y;
|
|
max.z -= temp.z;
|
|
*(rt_int16_t *)&cmd[1] = (rt_int16_t)max.x;
|
|
*(rt_int16_t *)&cmd[3] = (rt_int16_t)max.y;
|
|
*(rt_int16_t *)&cmd[5] = (rt_int16_t)max.z;
|
|
if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, cmd, sizeof(cmd)) == 0)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
accel_debug("Accel: Offset %+d %+d %+d\n", *(rt_int16_t *)&cmd[1], \
|
|
*(rt_int16_t *)&cmd[3], *(rt_int16_t *)&cmd[5]);
|
|
#endif
|
|
rt_thread_sleep(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Interact mode */
|
|
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;
|
|
}
|
|
|
|
accelInTime = true;
|
|
rt_timer_start(calTimer);
|
|
do
|
|
{
|
|
sum.x = 0x0;
|
|
sum.y = 0x0;
|
|
sum.z = 0x0;
|
|
|
|
for (i = 0; i < ACCEL_CAL_SAMPLES; i++)
|
|
{
|
|
#if (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
|
|
/* Waiting for data ready */
|
|
while(!GPIO_PinInGet(ACCEL_INT1_PORT, ACCEL_INT1_PIN));
|
|
#endif
|
|
if (efm_accel_get_data(&temp, false) != RT_EOK)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
sum.x += temp.x;
|
|
sum.y += temp.y;
|
|
sum.z += temp.z;
|
|
}
|
|
sum.x /= ACCEL_CAL_SAMPLES;
|
|
sum.y /= ACCEL_CAL_SAMPLES;
|
|
sum.z /= ACCEL_CAL_SAMPLES;
|
|
|
|
if (sum.x < min.x)
|
|
{
|
|
min.x = sum.x;
|
|
}
|
|
if (sum.y < min.y)
|
|
{
|
|
min.y = sum.y;
|
|
}
|
|
if (sum.z < min.z)
|
|
{
|
|
min.z = sum.z;
|
|
}
|
|
if (sum.x > max.x)
|
|
{
|
|
max.x = sum.x;
|
|
}
|
|
if (sum.y > max.y)
|
|
{
|
|
max.y = sum.y;
|
|
}
|
|
if (sum.z > max.z)
|
|
{
|
|
max.z = sum.z;
|
|
}
|
|
rt_thread_sleep(1);
|
|
} while (accelInTime);
|
|
|
|
accel_debug("Accel: Min %+d %+d %+d, max %+d %+d %+d\n",
|
|
min.x, min.y, min.z, max.x, max.y, max.z);
|
|
|
|
#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
|
|
accelOffset.x = -((min.x + max.x) >> 1);
|
|
accelOffset.y = -((min.y + max.y) >> 1);
|
|
accelOffset.z = -((min.z + max.z) >> 1);
|
|
|
|
accel_debug("Accel: Offset %+d %+d %+d\n",
|
|
accelOffset.x, accelOffset.y, accelOffset.z);
|
|
|
|
#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
|
|
/* Set offset drift registers */
|
|
*(rt_int16_t *)&cmd[1] = (rt_int16_t)-(min.x + max.x);
|
|
*(rt_int16_t *)&cmd[3] = (rt_int16_t)-(min.y + max.y);
|
|
*(rt_int16_t *)&cmd[5] = (rt_int16_t)-(min.z + max.z);
|
|
if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, cmd, sizeof(cmd)) == 0)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
accel_debug("Accel: Offset %+d %+d %+d\n",
|
|
*(rt_int16_t *)&cmd[1], *(rt_int16_t *)&cmd[3], *(rt_int16_t *)&cmd[5]);
|
|
#endif
|
|
|
|
rt_timer_delete(calTimer);
|
|
}
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Initialize the accelerometer
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
rt_err_t efm_accel_init(void)
|
|
{
|
|
rt_err_t ret;
|
|
|
|
ret = RT_EOK;
|
|
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);
|
|
ret = -RT_ERROR;
|
|
break;
|
|
}
|
|
accel_debug("Accel: Find device %s\n", ACCEL_USING_DEVICE_NAME);
|
|
|
|
/* --------- ADC interface --------- */
|
|
#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
|
|
ADC_InitScan_TypeDef scanInit = ADC_INITSCAN_DEFAULT;
|
|
|
|
#if defined(EFM32_GXXX_DK)
|
|
/* Enable accelerometer */
|
|
DVK_enablePeripheral(DVK_ACCEL);
|
|
/* Select g-range */
|
|
#if (ACCEL_G_SELECT == 0)
|
|
DVK_disablePeripheral(DVK_ACCEL_GSEL);
|
|
#elif (ACCEL_G_SELECT == 1)
|
|
DVK_enablePeripheral(DVK_ACCEL_GSEL);
|
|
#else
|
|
#error "Wrong value for ACCEL_G_SELECT"
|
|
#endif
|
|
#endif
|
|
/* 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;
|
|
if ((ret = accel->control(accel, RT_DEVICE_CTRL_ADC_MODE, \
|
|
(void *)&control)) != RT_EOK)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* --------- IIC interface --------- */
|
|
#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
|
|
rt_uint8_t cmd[2];
|
|
|
|
/* Initialize */
|
|
if ((ret = accel->control(accel, RT_DEVICE_CTRL_IIC_SETTING, \
|
|
(void *)&control)) != RT_EOK)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (efm_accel_config(
|
|
ACCEL_MODE_MEASUREMENT | ACCEL_RANGE_2G,
|
|
EFM32_NO_DATA,
|
|
EFM32_NO_DATA,
|
|
EFM32_NO_DATA,
|
|
EFM32_NO_DATA,
|
|
EFM32_NO_DATA) != RT_EOK)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* Config interrupt pin1 */
|
|
GPIO_PinModeSet(ACCEL_INT1_PORT, ACCEL_INT1_PIN, gpioModeInput, 0);
|
|
/* Config interrupt pin2 */
|
|
GPIO_PinModeSet(ACCEL_INT2_PORT, ACCEL_INT2_PIN, gpioModeInput, 0);
|
|
#endif
|
|
|
|
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_uint8_t mode, rt_uint32_t second)
|
|
{
|
|
if (efm_accel_auto_zero(mode, RT_TICK_PER_SECOND * second) != RT_EOK)
|
|
{
|
|
rt_kprintf("Error occurred.");
|
|
return;
|
|
}
|
|
|
|
rt_kprintf("Calibration done.\n");
|
|
}
|
|
FINSH_FUNCTION_EXPORT(accel_cal, auto-zero calibration.)
|
|
|
|
void list_accel(void)
|
|
{
|
|
struct efm32_accel_result_t data;
|
|
|
|
efm_accel_get_data(&data, false);
|
|
rt_kprintf("X: %d, Y: %d, Z: %d\n", data.x, data.y, data.z);
|
|
}
|
|
FINSH_FUNCTION_EXPORT(list_accel, list accelerometer info.)
|
|
|
|
void test_accel(rt_uint8_t mode)
|
|
{
|
|
if (mode == 0)
|
|
{
|
|
if (efm_accel_config(
|
|
ACCEL_MODE_LEVEL | ACCEL_RANGE_8G | ACCEL_INT_LEVEL_PULSE | \
|
|
ACCEL_SOURCE_LEVEL_X | ACCEL_SOURCE_LEVEL_Y,
|
|
0x1f,
|
|
EFM32_NO_DATA,
|
|
EFM32_NO_DATA,
|
|
EFM32_NO_DATA,
|
|
EFM32_NO_DATA) != RT_EOK)
|
|
{
|
|
rt_kprintf("efm_accel_config(): error\n");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (efm_accel_config(
|
|
ACCEL_MODE_PULSE | ACCEL_RANGE_8G | ACCEL_INT_SINGLE_DOUBLE | \
|
|
ACCEL_SOURCE_PULSE_X | ACCEL_SOURCE_PULSE_Y,
|
|
0x1f,
|
|
0x1f,
|
|
200,
|
|
255,
|
|
255) != RT_EOK)
|
|
{
|
|
rt_kprintf("efm_accel_config(): error\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
FINSH_FUNCTION_EXPORT(test_accel, list accelerometer info.)
|
|
#endif
|
|
|
|
#endif
|
|
/***************************************************************************//**
|
|
* @}
|
|
******************************************************************************/
|