*** EFM32 branch ***
1. Change the usage of the second parameter of Read and Write functions in IIC driver - to "Slave address" from (seldom used) "Offset" 2. Add a timer for IIC driver to prevent from forever waiting 3. Add digital (IIC) interface support for accelerometer driver (Freescale MMA7455L) git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1678 bbd45198-f89e-11dd-88c7-29a3b14d5316
This commit is contained in:
parent
da55b1857f
commit
11488d143a
|
@ -13,6 +13,8 @@
|
|||
* 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
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
|
@ -22,25 +24,37 @@
|
|||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "board.h"
|
||||
#include "drv_adc.h"
|
||||
#include "dev_accel.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 RT_ACCEL_DEBUG
|
||||
#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;
|
||||
static struct efm32_adc_control_t control = \
|
||||
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};
|
||||
static rt_bool_t accelInTime = true;
|
||||
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 -----------------------------------------------*/
|
||||
|
@ -56,26 +70,97 @@ static rt_bool_t accelInTime = true;
|
|||
* @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_err_t efm_accel_get_data(struct efm32_accel_result_t *data,
|
||||
rt_bool_t lowResolution)
|
||||
{
|
||||
RT_ASSERT(accel != RT_NULL);
|
||||
|
||||
struct efm32_adc_result_t result;
|
||||
rt_err_t ret;
|
||||
|
||||
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);
|
||||
ret = RT_EOK;
|
||||
do
|
||||
{
|
||||
/* --------- ADC interface --------- */
|
||||
#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
|
||||
struct efm32_adc_result_t result;
|
||||
|
||||
return RT_EOK;
|
||||
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;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
|
@ -94,6 +179,354 @@ 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
|
||||
|
@ -102,76 +535,203 @@ static void efm_accel_timer(void* parameter)
|
|||
*
|
||||
* @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_tick_t period)
|
||||
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 = {0x7ff, 0x7ff, 0x7ff};
|
||||
struct efm32_accel_result_t max = {0x7ff, 0x7ff, 0x7ff};
|
||||
struct efm32_accel_result_t temp;
|
||||
struct efm32_adc_result_t result;
|
||||
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;
|
||||
|
||||
if ((calTimer = rt_timer_create(
|
||||
"cal_tmr",
|
||||
efm_accel_timer,
|
||||
RT_NULL,
|
||||
period,
|
||||
RT_TIMER_FLAG_ONE_SHOT)) == RT_NULL)
|
||||
/* 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)
|
||||
{
|
||||
accel_debug("Accel err: Create timer failed!\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
result.mode = control.mode;
|
||||
result.buffer = (void *)&temp;
|
||||
accelInTime = true;
|
||||
rt_timer_start(calTimer);
|
||||
do
|
||||
if (mode == ACCEL_CAL_SIMPLE)
|
||||
{
|
||||
accel->control(accel, RT_DEVICE_CTRL_RESUME, &result);
|
||||
accel->control(accel, RT_DEVICE_CTRL_ADC_RESULT, &result);
|
||||
if (temp.x < min.x)
|
||||
/* Simple mode */
|
||||
for (j = 0; j < ACCEL_CAL_ROUND; j++)
|
||||
{
|
||||
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);
|
||||
sum.x = 0x0;
|
||||
sum.y = 0x0;
|
||||
sum.z = 0x0;
|
||||
|
||||
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,
|
||||
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);
|
||||
|
||||
rt_timer_delete(calTimer);
|
||||
#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;
|
||||
}
|
||||
|
||||
|
@ -188,15 +748,9 @@ rt_err_t efm_accel_auto_zero(rt_tick_t period)
|
|||
******************************************************************************/
|
||||
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
|
||||
rt_err_t ret;
|
||||
|
||||
ret = RT_EOK;
|
||||
do
|
||||
{
|
||||
/* Find ADC device */
|
||||
|
@ -204,16 +758,65 @@ rt_err_t efm_accel_init(void)
|
|||
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_G290_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;
|
||||
accel->control(accel, RT_DEVICE_CTRL_ADC_MODE, &control);
|
||||
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;
|
||||
|
@ -229,35 +832,61 @@ rt_err_t efm_accel_init(void)
|
|||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
|
||||
void accel_cal(rt_uint32_t second)
|
||||
void accel_cal(rt_uint8_t mode, rt_uint32_t second)
|
||||
{
|
||||
efm_accel_auto_zero(RT_TICK_PER_SECOND * second);
|
||||
if (efm_accel_auto_zero(mode, RT_TICK_PER_SECOND * second) != RT_EOK)
|
||||
{
|
||||
rt_kprintf("Error occurred.");
|
||||
return;
|
||||
}
|
||||
|
||||
rt_kprintf("Calibration done. Offset: 0x%03x, 0x%03x, 0x%03x\n",
|
||||
accelOffset.x, accelOffset.y, accelOffset.z);
|
||||
rt_kprintf("Calibration done.\n");
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(accel_cal, auto-zero calibration.)
|
||||
|
||||
void list_accel(void)
|
||||
{
|
||||
struct efm32_accel_result_t temp;
|
||||
rt_int32_t x, y, z;
|
||||
struct efm32_accel_result_t data;
|
||||
|
||||
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);
|
||||
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
|
||||
|
|
|
@ -13,28 +13,110 @@
|
|||
* 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
|
||||
******************************************************************************/
|
||||
#ifndef __DEV_ACCEL_H__
|
||||
#define __DEV_ACCEL_H__
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#if (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
|
||||
#include "mma7455l.h"
|
||||
#endif
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
struct efm32_accel_result_t
|
||||
{
|
||||
rt_uint32_t x;
|
||||
rt_uint32_t y;
|
||||
rt_uint32_t z;
|
||||
rt_int32_t x;
|
||||
rt_int32_t y;
|
||||
rt_int32_t z;
|
||||
};
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
#define ACCEL_X_ADC_CH ADC_SCANCTRL_INPUTMASK_CH2
|
||||
#define ACCEL_Y_ADC_CH ADC_SCANCTRL_INPUTMASK_CH3
|
||||
#define ACCEL_Z_ADC_CH ADC_SCANCTRL_INPUTMASK_CH4
|
||||
/* MMA7361LC
|
||||
g-Select g-Range Sensitivity
|
||||
0 1.5 g 800 mV/g
|
||||
1 6 g 206 mV/g
|
||||
|
||||
MMA7455L
|
||||
g-Select g-Range Sensitivity
|
||||
0 2 g 64 LSB/g
|
||||
1 4 g 32 LSB/g
|
||||
2 8 g 16 LSB/g
|
||||
*/
|
||||
#define ACCEL_G_SELECT (0)
|
||||
|
||||
#define ACCEL_CAL_SAMPLES (4) /* Must be multiple of 2 */
|
||||
#define ACCEL_CAL_ROUND (50)
|
||||
#define ACCEL_CAL_SIMPLE (0)
|
||||
#define ACCEL_CAL_INTERACT (1)
|
||||
|
||||
#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
|
||||
/* Reading_at_1g = Sensitivity * Max_reading / Refference_voltage */
|
||||
#define ACCEL_CAL_1G_VALUE {993, 256}
|
||||
|
||||
#define ACCEL_X_ADC_CH ADC_SCANCTRL_INPUTMASK_CH2
|
||||
#define ACCEL_Y_ADC_CH ADC_SCANCTRL_INPUTMASK_CH3
|
||||
#define ACCEL_Z_ADC_CH ADC_SCANCTRL_INPUTMASK_CH4
|
||||
#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
|
||||
#define ACCEL_CAL_1G_VALUE {0x3f, 0x1f, 0x0f}
|
||||
#define ACCEL_IIC_SLAVE_ADDRESS (0x1d)
|
||||
|
||||
#define ACCEL_INT1_PORT (gpioPortD)
|
||||
#define ACCEL_INT1_PIN (13)
|
||||
#define ACCEL_INT2_PORT (gpioPortD)
|
||||
#define ACCEL_INT2_PIN (12)
|
||||
|
||||
#define ACCEL_MODE_STANDBY (1 << 0)
|
||||
#define ACCEL_MODE_MEASUREMENT (1 << 1)
|
||||
#define ACCEL_MODE_LEVEL (1 << 2)
|
||||
#define ACCEL_MODE_PULSE (1 << 3)
|
||||
#define ACCEL_RANGE_8G (1 << 4)
|
||||
#define ACCEL_RANGE_4G (1 << 5)
|
||||
#define ACCEL_RANGE_2G (1 << 6)
|
||||
#define ACCEL_INTPIN_INVERSE (1 << 7)
|
||||
#define ACCEL_INT_LEVEL_PULSE (1 << 8)
|
||||
#define ACCEL_INT_PULSE_LEVEL (1 << 9)
|
||||
#define ACCEL_INT_SINGLE_DOUBLE (1 << 10)
|
||||
#define ACCEL_DISABLE_X (1 << 11)
|
||||
#define ACCEL_DISABLE_Y (1 << 12)
|
||||
#define ACCEL_DISABLE_Z (1 << 13)
|
||||
#define ACCEL_THRESHOLD_INTEGER (1 << 14) /* For level detection only */
|
||||
#define ACCEL_BANDWIDTH_125HZ (1 << 15)
|
||||
#define ACCEL_LEVEL_AND (1 << 16)
|
||||
#define ACCEL_PULSE_AND (1 << 17)
|
||||
#define ACCEL_DRIVE_STRONG (1 << 18)
|
||||
#define ACCEL_SOURCE_LEVEL_X (1 << 19)
|
||||
#define ACCEL_SOURCE_LEVEL_Y (1 << 20)
|
||||
#define ACCEL_SOURCE_LEVEL_Z (1 << 21)
|
||||
#define ACCEL_SOURCE_PULSE_X (1 << 22)
|
||||
#define ACCEL_SOURCE_PULSE_Y (1 << 23)
|
||||
#define ACCEL_SOURCE_PULSE_Z (1 << 24)
|
||||
|
||||
#define ACCEL_SHIFT_MODE (0)
|
||||
#define ACCEL_SHIFT_RANGE (4)
|
||||
#define ACCEL_SHIFT_INT (8)
|
||||
#define ACCEL_SHIFT_DISABLE (11)
|
||||
#define ACCEL_SHIFT_SOURCE (19)
|
||||
|
||||
#define ACCEL_MASK_MODE (0X0000000f << ACCEL_SHIFT_MODE)
|
||||
#define ACCEL_MASK_RANGE (0X00000007 << ACCEL_SHIFT_RANGE)
|
||||
#define ACCEL_MASK_INT (0X00000007 << ACCEL_SHIFT_INT)
|
||||
#define ACCEL_MASK_DISABLE (0X00000007 << ACCEL_SHIFT_DISABLE)
|
||||
#define ACCEL_MASK_SOURCE (0X0000003f << ACCEL_SHIFT_SOURCE)
|
||||
#endif
|
||||
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
rt_err_t efm_accel_get_data(struct efm32_accel_result_t *data);
|
||||
rt_err_t efm_accel_auto_zero(rt_tick_t period);
|
||||
rt_err_t efm_accel_get_data(struct efm32_accel_result_t *data,
|
||||
rt_bool_t lowResolution);
|
||||
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 efm_accel_auto_zero(rt_uint8_t mode, rt_tick_t period);
|
||||
rt_err_t efm_accel_init(void);
|
||||
|
||||
#endif /*__DEV_ACCEL_H__ */
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
* 2011-06-17 onelife Modify init function for efm32lib v2 upgrading
|
||||
* 2011-07-11 onelife Add lock (semaphore) to prevent simultaneously
|
||||
* access
|
||||
* 2011-08-04 onelife Change the usage of the second parameter of Read
|
||||
* and Write functions from (seldom used) "Offset" to "Slave address"
|
||||
* 2011-08-04 onelife Add a timer to prevent from forever waiting
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
|
@ -29,6 +32,13 @@
|
|||
|
||||
#if (defined(RT_USING_IIC0) || defined(RT_USING_IIC1))
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
struct efm32_iic_block
|
||||
{
|
||||
struct rt_device device;
|
||||
struct rt_semaphore lock;
|
||||
struct rt_timer timer;
|
||||
};
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
#ifdef RT_IIC_DEBUG
|
||||
|
@ -39,19 +49,17 @@
|
|||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
#ifdef RT_USING_IIC0
|
||||
#if (RT_USING_IIC0 > 3)
|
||||
#error "The location number range of IIC is 0~3"
|
||||
#endif
|
||||
struct rt_device iic0_device;
|
||||
static struct rt_semaphore iic0_lock;
|
||||
#if (RT_USING_IIC0 > 3)
|
||||
#error "The location number range of IIC is 0~3"
|
||||
#endif
|
||||
static struct efm32_iic_block iic0;
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_IIC1
|
||||
#if (RT_USING_IIC1 > 3)
|
||||
#error "The location number range of IIC is 0~3"
|
||||
#endif
|
||||
struct rt_device iic1_device;
|
||||
static struct rt_semaphore iic1_lock;
|
||||
#if (RT_USING_IIC1 > 3)
|
||||
#error "The location number range of IIC is 0~3"
|
||||
#endif
|
||||
static struct efm32_iic_block iic1;
|
||||
#endif
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
|
@ -161,7 +169,7 @@ static rt_err_t rt_iic_close(rt_device_t dev)
|
|||
* Pointer to device descriptor
|
||||
*
|
||||
* @param[in] pos
|
||||
* Offset
|
||||
* Slave address
|
||||
*
|
||||
* @param[in] buffer
|
||||
* Poniter to the buffer
|
||||
|
@ -183,7 +191,6 @@ static rt_size_t rt_iic_read (
|
|||
struct efm32_iic_device_t* iic;
|
||||
I2C_TransferSeq_TypeDef seq;
|
||||
I2C_TransferReturn_TypeDef ret;
|
||||
rt_uint8_t data[1];
|
||||
|
||||
if (!size)
|
||||
{
|
||||
|
@ -193,7 +200,6 @@ static rt_size_t rt_iic_read (
|
|||
err_code = RT_EOK;
|
||||
read_size = 0;
|
||||
iic = (struct efm32_iic_device_t*)dev->user_data;
|
||||
data[0] = (rt_uint8_t)(pos & 0x000000FF);
|
||||
|
||||
/* Lock device */
|
||||
if (rt_hw_interrupt_check())
|
||||
|
@ -211,36 +217,39 @@ static rt_size_t rt_iic_read (
|
|||
|
||||
if (iic->state & IIC_STATE_MASTER)
|
||||
{
|
||||
seq.addr = iic->slave_address;
|
||||
seq.addr = (rt_uint16_t)pos << 1;
|
||||
seq.flags = I2C_FLAG_WRITE_READ;
|
||||
/* Select register to be read */
|
||||
seq.buf[0].data = data;
|
||||
/* Set register to be read */
|
||||
seq.buf[0].data = (rt_uint8_t *)buffer;
|
||||
seq.buf[0].len = 1;
|
||||
/* Select location/length of data to be read */
|
||||
/* Set read buffer pointer and size */
|
||||
seq.buf[1].data = (rt_uint8_t *)buffer;
|
||||
seq.buf[1].len = size;
|
||||
|
||||
/* Do a polled transfer */
|
||||
iic->timeout = false;
|
||||
rt_timer_stop(iic->timer);
|
||||
rt_timer_start(iic->timer);
|
||||
ret = I2C_TransferInit(iic->iic_device, &seq);
|
||||
while (ret == i2cTransferInProgress)
|
||||
while ((ret == i2cTransferInProgress) && !iic->timeout)
|
||||
{
|
||||
ret = I2C_Transfer(iic->iic_device);
|
||||
}
|
||||
|
||||
if (ret != i2cTransferDone)
|
||||
{
|
||||
iic_debug("IIC0 read error: %x\n", ret);
|
||||
iic_debug("IIC0 read address: %x\n", seq.addr);
|
||||
iic_debug("IIC0 read data0: %x -> %x\n", seq.buf[0].data, *seq.buf[0].data);
|
||||
iic_debug("IIC0 read len0: %x\n", seq.buf[0].len);
|
||||
iic_debug("IIC0 read data1: %x -> %x\n", seq.buf[1].data, *seq.buf[1].data);
|
||||
iic_debug("IIC0 read len1: %x\n", seq.buf[1].len);
|
||||
iic_debug("IIC read error: %x\n", ret);
|
||||
iic_debug("IIC read address: %x\n", seq.addr);
|
||||
iic_debug("IIC read data0: %x -> %x\n", seq.buf[0].data, *seq.buf[0].data);
|
||||
iic_debug("IIC read len0: %x\n", seq.buf[0].len);
|
||||
iic_debug("IIC read data1: %x -> %x\n", seq.buf[1].data, *seq.buf[1].data);
|
||||
iic_debug("IIC read len1: %x\n", seq.buf[1].len);
|
||||
err_code = (rt_err_t)ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_size = size;
|
||||
iic_debug("IIC0 read size: %d\n", read_size);
|
||||
iic_debug("IIC read size: %d\n", read_size);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -288,7 +297,7 @@ static rt_size_t rt_iic_read (
|
|||
}
|
||||
|
||||
read_size = (rt_uint32_t)ptr - (rt_uint32_t)buffer;
|
||||
iic_debug("IIC0 slave read size: %d\n", read_size);
|
||||
iic_debug("IIC slave read size: %d\n", read_size);
|
||||
}
|
||||
|
||||
/* Unlock device */
|
||||
|
@ -311,7 +320,7 @@ static rt_size_t rt_iic_read (
|
|||
* Pointer to device descriptor
|
||||
*
|
||||
* @param[in] pos
|
||||
* Offset
|
||||
* Slave address
|
||||
*
|
||||
* @param[in] buffer
|
||||
* Poniter to the buffer
|
||||
|
@ -359,24 +368,11 @@ static rt_size_t rt_iic_write (
|
|||
|
||||
if (iic->state & IIC_STATE_MASTER)
|
||||
{
|
||||
seq.addr = iic->slave_address;
|
||||
if (pos != (rt_off_t)(-1))
|
||||
{
|
||||
seq.flags = I2C_FLAG_WRITE_WRITE;
|
||||
/* Select register to be write */
|
||||
seq.buf[0].data = (rt_uint8_t *)(pos & 0x000000FF);
|
||||
seq.buf[0].len = 1;
|
||||
/* Select location/length of data to be write */
|
||||
seq.buf[1].data = (rt_uint8_t *)buffer;
|
||||
seq.buf[1].len = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
seq.flags = I2C_FLAG_WRITE;
|
||||
/* Select location/length of data to be write */
|
||||
seq.buf[0].data = (rt_uint8_t *)buffer;
|
||||
seq.buf[0].len = size;
|
||||
}
|
||||
seq.addr = (rt_uint16_t)pos << 1;
|
||||
seq.flags = I2C_FLAG_WRITE;
|
||||
/* Set write buffer pointer and size */
|
||||
seq.buf[0].data = (rt_uint8_t *)buffer;
|
||||
seq.buf[0].len = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -384,10 +380,13 @@ static rt_size_t rt_iic_write (
|
|||
}
|
||||
|
||||
/* Do a polled transfer */
|
||||
iic->timeout = false;
|
||||
rt_timer_stop(iic->timer);
|
||||
rt_timer_start(iic->timer);
|
||||
ret = I2C_TransferInit(iic->iic_device, &seq);
|
||||
while (ret == i2cTransferInProgress)
|
||||
while ((ret == i2cTransferInProgress) && !iic->timeout)
|
||||
{
|
||||
ret = I2C_Transfer(iic->iic_device);
|
||||
ret = I2C_Transfer(iic->iic_device);
|
||||
}
|
||||
|
||||
if (ret != i2cTransferDone)
|
||||
|
@ -474,8 +473,7 @@ static rt_err_t rt_iic_control (
|
|||
|
||||
control = (struct efm32_iic_control_t *)args;
|
||||
iic->state = control->config & (IIC_STATE_MASTER | IIC_STATE_BROADCAST);
|
||||
iic->master_address = control->master_address << 1;
|
||||
iic->slave_address = control->slave_address << 1;
|
||||
iic->address = control->address << 1;
|
||||
|
||||
if (!(iic->state & IIC_STATE_MASTER))
|
||||
{
|
||||
|
@ -503,7 +501,7 @@ static rt_err_t rt_iic_control (
|
|||
}
|
||||
|
||||
/* Enable slave mode */
|
||||
I2C_SlaveAddressSet(iic->iic_device, iic->slave_address);
|
||||
I2C_SlaveAddressSet(iic->iic_device, iic->address);
|
||||
I2C_SlaveAddressMaskSet(iic->iic_device, 0xFF);
|
||||
iic->iic_device->CTRL |= I2C_CTRL_SLAVE | I2C_CTRL_AUTOACK | I2C_CTRL_AUTOSN;
|
||||
|
||||
|
@ -513,7 +511,7 @@ static rt_err_t rt_iic_control (
|
|||
|
||||
/* Enable I2Cn interrupt vector in NVIC */
|
||||
#ifdef RT_USING_IIC0
|
||||
if (dev == &iic0_device)
|
||||
if (dev == &iic0.device)
|
||||
{
|
||||
NVIC_ClearPendingIRQ(I2C0_IRQn);
|
||||
NVIC_SetPriority(I2C0_IRQn, EFM32_IRQ_PRI_DEFAULT);
|
||||
|
@ -521,7 +519,7 @@ static rt_err_t rt_iic_control (
|
|||
}
|
||||
#endif
|
||||
#ifdef RT_USING_IIC1
|
||||
if (dev == &iic1_device)
|
||||
if (dev == &iic1.device)
|
||||
{
|
||||
NVIC_ClearPendingIRQ(I2C1_IRQn);
|
||||
NVIC_SetPriority(I2C1_IRQn, EFM32_IRQ_PRI_DEFAULT);
|
||||
|
@ -539,6 +537,22 @@ static rt_err_t rt_iic_control (
|
|||
return RT_EOK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* IIC timeout interrupt handler
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* @note
|
||||
*
|
||||
* @param[in] parameter
|
||||
* Parameter
|
||||
******************************************************************************/
|
||||
static void rt_iic_timer(void *timeout)
|
||||
{
|
||||
*(rt_bool_t *)timeout = true;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Register IIC device
|
||||
|
@ -683,14 +697,15 @@ static void rt_hw_iic_slave_isr(rt_device_t dev)
|
|||
* Pin location number
|
||||
******************************************************************************/
|
||||
static struct efm32_iic_device_t *rt_hw_iic_unit_init(
|
||||
rt_device_t device,
|
||||
rt_uint8_t unitNumber,
|
||||
rt_uint8_t location)
|
||||
struct efm32_iic_block *block,
|
||||
rt_uint8_t unitNumber,
|
||||
rt_uint8_t location)
|
||||
{
|
||||
struct efm32_iic_device_t *iic;
|
||||
CMU_Clock_TypeDef iicClock;
|
||||
I2C_Init_TypeDef init = I2C_INIT_DEFAULT;
|
||||
efm32_irq_hook_init_t hook;
|
||||
rt_uint8_t name[RT_NAME_MAX];
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -702,9 +717,10 @@ static struct efm32_iic_device_t *rt_hw_iic_unit_init(
|
|||
break;
|
||||
}
|
||||
iic->counter = 0;
|
||||
iic->timer = &block->timer;
|
||||
iic->timeout = false;
|
||||
iic->state |= IIC_STATE_MASTER;
|
||||
iic->master_address = 0x0000;
|
||||
iic->slave_address = 0x0000;
|
||||
iic->address = 0x0000;
|
||||
iic->rx_buffer = RT_NULL;
|
||||
|
||||
/* Initialization */
|
||||
|
@ -729,6 +745,7 @@ static struct efm32_iic_device_t *rt_hw_iic_unit_init(
|
|||
default:
|
||||
break;
|
||||
}
|
||||
rt_sprintf(name, "iic%d", unitNumber);
|
||||
|
||||
/* Enabling clock */
|
||||
CMU_ClockEnable(iicClock, true);
|
||||
|
@ -751,7 +768,7 @@ static struct efm32_iic_device_t *rt_hw_iic_unit_init(
|
|||
hook.type = efm32_irq_type_iic;
|
||||
hook.unit = unitNumber;
|
||||
hook.cbFunc = rt_hw_iic_slave_isr;
|
||||
hook.userPtr = device;
|
||||
hook.userPtr = (void *)&block->device;
|
||||
efm32_irq_hook_register(&hook);
|
||||
|
||||
/* Enable SDZ and SCL pins and set location */
|
||||
|
@ -765,6 +782,17 @@ static struct efm32_iic_device_t *rt_hw_iic_unit_init(
|
|||
/* Abort current TX data and clear TX buffers */
|
||||
iic->iic_device->CMD = I2C_CMD_ABORT | I2C_CMD_CLEARPC | I2C_CMD_CLEARTX;
|
||||
|
||||
/* Initialize lock */
|
||||
iic->lock = &block->lock;
|
||||
if (rt_sem_init(iic->lock, name, 1, RT_IPC_FLAG_FIFO) != RT_EOK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Initialize timer */
|
||||
rt_timer_init(iic->timer, name, rt_iic_timer, &iic->timeout,
|
||||
IIC_TIMEOUT_PERIOD, RT_TIMER_FLAG_ONE_SHOT);
|
||||
|
||||
return iic;
|
||||
} while(0);
|
||||
|
||||
|
@ -795,40 +823,26 @@ void rt_hw_iic_init(void)
|
|||
flag = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX;
|
||||
#ifdef RT_USING_IIC0
|
||||
/* Initialize and register iic0 */
|
||||
if ((iic = rt_hw_iic_unit_init(&iic0_device, 0, RT_USING_IIC0)) != RT_NULL)
|
||||
if ((iic = rt_hw_iic_unit_init(&iic0, 0, RT_USING_IIC0)) != RT_NULL)
|
||||
{
|
||||
rt_hw_iic_register(&iic0_device, RT_IIC0_NAME, flag, iic);
|
||||
rt_hw_iic_register(&iic0.device, RT_IIC0_NAME, flag, iic);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Initialize lock for iic0 */
|
||||
iic->lock = &iic0_lock;
|
||||
if (rt_sem_init(iic->lock, RT_IIC0_NAME, 1, RT_IPC_FLAG_FIFO) != RT_EOK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_IIC1
|
||||
/* Initialize and register iic1 */
|
||||
if ((iic = rt_hw_iic_unit_init(&iic1_device, 1, RT_USING_IIC1)) != RT_NULL)
|
||||
if ((iic = rt_hw_iic_unit_init(&iic1, 1, RT_USING_IIC1)) != RT_NULL)
|
||||
{
|
||||
rt_hw_iic_register(&iic1_device, RT_IIC1_NAME, flag, iic);
|
||||
rt_hw_iic_register(&iic1.device, RT_IIC1_NAME, flag, iic);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Initialize lock for iic1 */
|
||||
iic->lock = &iic1_lock;
|
||||
if (rt_sem_init(iic->lock, RT_IIC1_NAME, 1, RT_IPC_FLAG_FIFO) != RT_EOK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
iic_debug("IIC: H/W init OK!\n");
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
* 2011-01-07 onelife Initial creation for EFM32
|
||||
* 2011-07-11 onelife Add lock (semaphore) to prevent simultaneously
|
||||
* access
|
||||
* 2011-08-04 onelife Change the usage of the second parameter of Read
|
||||
* and Write functions from (seldom used) "Offset" to "Slave address"
|
||||
* 2011-08-04 onelife Add a timer to prevent from forever waiting
|
||||
******************************************************************************/
|
||||
#ifndef __DRV_IIC_H__
|
||||
#define __DRV_IIC_H__
|
||||
|
@ -33,14 +36,16 @@ struct efm32_iic_device_t
|
|||
rt_uint32_t counter;
|
||||
/* Lock */
|
||||
struct rt_semaphore *lock;
|
||||
/* Pointer to timer */
|
||||
rt_timer_t timer;
|
||||
/* Timeout flag */
|
||||
volatile rt_bool_t timeout;
|
||||
/* State */
|
||||
rt_uint8_t state;
|
||||
/* Pointer to IIC device structure */
|
||||
I2C_TypeDef *iic_device;
|
||||
/* Master address */
|
||||
rt_uint16_t master_address;
|
||||
/* Slave address */
|
||||
rt_uint16_t slave_address;
|
||||
/* Self address */
|
||||
rt_uint16_t address;
|
||||
/* RX structure */
|
||||
struct efm32_iic_int_mode_t *rx_buffer;
|
||||
};
|
||||
|
@ -48,8 +53,7 @@ struct efm32_iic_device_t
|
|||
struct efm32_iic_control_t
|
||||
{
|
||||
rt_uint8_t config;
|
||||
rt_uint16_t master_address;
|
||||
rt_uint16_t slave_address;
|
||||
rt_uint16_t address;
|
||||
};
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
|
@ -58,6 +62,7 @@ struct efm32_iic_control_t
|
|||
#define IIC_STATE_BROADCAST (1 << 1)
|
||||
//#define IIC_STATE_TX_BUSY (1 << 2)
|
||||
#define IIC_STATE_RX_BUSY (1 << 3)
|
||||
#define IIC_TIMEOUT_PERIOD (RT_TICK_PER_SECOND)
|
||||
|
||||
/* Exported functions --------------------------------------------------------*/
|
||||
void rt_hw_iic_init(void);
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
//#define RT_RTC_DEBUG
|
||||
|
||||
#define EFM32_DEBUG
|
||||
#define RT_ACCEL_DEBUG
|
||||
#define EFM32_ACCEL_DEBUG
|
||||
#define EFM32_SFLASH_DEBUG
|
||||
//#define EFM32_SDCARD_DEBUG
|
||||
//#define EFM32_ETHERNET_DEBUG
|
||||
|
@ -119,7 +119,7 @@
|
|||
#endif
|
||||
|
||||
/* SECTION: IIC options */
|
||||
//#define RT_USING_IIC0 0x1UL
|
||||
#define RT_USING_IIC0 0x3UL
|
||||
#define RT_IIC0_NAME "iic0"
|
||||
|
||||
/* SECTION: ACMP options */
|
||||
|
@ -162,23 +162,34 @@
|
|||
#define FINSH_USING_DESCRIPTION
|
||||
|
||||
/* SECTION: Peripheral devices */
|
||||
#define EFM32_INTERFACE_ADC (0)
|
||||
#define EFM32_INTERFACE_IIC (1)
|
||||
#define EFM32_INTERFACE_SPI (2)
|
||||
#if defined(EFM32_G290_DK)
|
||||
//#define EFM32_USING_ACCEL /* Three axis accelerometer */
|
||||
//#define EFM32_USING_SFLASH /* SPI Flash */
|
||||
//#define EFM32_USING_SPISD /* MicroSD card */
|
||||
#define EFM32_USING_ETHERNET /* Ethernet controller */
|
||||
#define EFM32_USING_ACCEL EFM32_INTERFACE_IIC /* Three axis accelerometer */
|
||||
//#define EFM32_USING_SFLASH /* SPI Flash */
|
||||
//#define EFM32_USING_SPISD /* MicroSD card */
|
||||
//#define EFM32_USING_ETHERNET /* Ethernet controller */
|
||||
#endif
|
||||
|
||||
#if defined(EFM32_USING_ACCEL)
|
||||
#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
|
||||
#define ACCEL_USING_DEVICE_NAME RT_ADC0_NAME
|
||||
#define ACCEL_USING_DMA (0x3UL)
|
||||
#define ACCEL_USING_DMA (0x3UL) /* For multiple channels scan mode */
|
||||
#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
|
||||
#define ACCEL_USING_DEVICE_NAME RT_IIC0_NAME
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(EFM32_USING_SFLASH)
|
||||
#define SFLASH_USING_DEVICE_NAME RT_USART0_NAME
|
||||
#endif
|
||||
|
||||
#if defined(EFM32_USING_SPISD)
|
||||
#define SPISD_USING_DEVICE_NAME RT_USART0_NAME
|
||||
#define SPISD_DEVICE_NAME "spiSd"
|
||||
#endif
|
||||
|
||||
#if defined(EFM32_USING_ETHERNET)
|
||||
#define ETH_USING_DEVICE_NAME RT_USART2_NAME
|
||||
#define ETH_DEVICE_NAME "spiEth"
|
||||
|
@ -205,7 +216,7 @@
|
|||
//#define hostName "onelife.dyndns.org"
|
||||
//#define userPwdB64 "dXNlcjpwYXNzd2Q="
|
||||
|
||||
#define RT_USING_LWIP
|
||||
///#define RT_USING_LWIP
|
||||
//#define RT_USING_NETUTILS
|
||||
/* LwIP uses RT-Thread Memory Management */
|
||||
#define RT_LWIP_USING_RT_MEM
|
||||
|
|
Loading…
Reference in New Issue