summaryrefslogtreecommitdiff
path: root/bsp
diff options
context:
space:
mode:
authoronelife.real <[email protected]>2011-08-23 00:59:24 +0000
committeronelife.real <[email protected]>2011-08-23 00:59:24 +0000
commit11488d143a0a344e4512fac2808f894f945239a3 (patch)
treee7eaafbf74277a6935f491181bdbb5c650a6537b /bsp
parentda55b1857f727d834496874b722d2c4322aa9ad5 (diff)
*** 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
Diffstat (limited to 'bsp')
-rw-r--r--bsp/efm32/dev_accel.c795
-rw-r--r--bsp/efm32/dev_accel.h98
-rw-r--r--bsp/efm32/drv_iic.c166
-rw-r--r--bsp/efm32/drv_iic.h17
-rw-r--r--bsp/efm32/rtconfig.h27
5 files changed, 922 insertions, 181 deletions
diff --git a/bsp/efm32/dev_accel.c b/bsp/efm32/dev_accel.c
index b0423e227c..989e498279 100644
--- a/bsp/efm32/dev_accel.c
+++ b/bsp/efm32/dev_accel.c
@@ -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"
+
+#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"
-#if defined(EFM32_USING_ACCEL)
/* 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,84 +179,559 @@ static void efm_accel_timer(void* parameter)
accelInTime = false;
}
+#if (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
/***************************************************************************//**
* @brief
- * Accelerometer auto-zero calibration function
+ * Accelerometer level and pulse detection interrupts handler
*
* @details
*
* @note
*
- * @param[in] period
- * Time period to perform auto-zero calibration
+ * @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_auto_zero(rt_tick_t period)
+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_ASSERT(accel != RT_NULL);
+ rt_err_t ret;
+ rt_uint8_t buf[2];
+ rt_uint8_t mode, mctl_reg, ctl1_reg, ctl2_reg;
- 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;
+ 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;
+ }
- if ((calTimer = rt_timer_create(
- "cal_tmr",
- efm_accel_timer,
- RT_NULL,
- period,
- RT_TIMER_FLAG_ONE_SHOT)) == RT_NULL)
+ switch (config & ACCEL_MASK_RANGE)
{
- accel_debug("Accel err: Create timer failed!\n");
+ 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;
}
- result.mode = control.mode;
- result.buffer = (void *)&temp;
- accelInTime = true;
- rt_timer_start(calTimer);
+ 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
{
- accel->control(accel, RT_DEVICE_CTRL_RESUME, &result);
- accel->control(accel, RT_DEVICE_CTRL_ADC_RESULT, &result);
- if (temp.x < min.x)
+ /* Write registers */
+ buf[0] = MCTL;
+ buf[1] = mctl_reg;
+ if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
{
- min.x = temp.x;
+ ret = -RT_ERROR;
+ break;
}
- if (temp.y < min.y)
+ 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)
{
- min.y = temp.y;
+ ret = -RT_ERROR;
+ break;
}
- if (temp.z < min.z)
+ 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)
{
- min.z = temp.z;
+ 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 (temp.x > max.x)
+
+ if ((mode == ACCEL_MODE_LEVEL) || (mode == ACCEL_MODE_PULSE))
{
- max.x = temp.x;
+ 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;
+ }
}
- if (temp.y > max.y)
+ } 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++)
{
- max.y = temp.y;
+ 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);
}
- if (temp.z > max.z)
+ }
+ else
+ {
+ /* Interact mode */
+ if ((calTimer = rt_timer_create(
+ "cal_tmr",
+ efm_accel_timer,
+ RT_NULL,
+ period,
+ RT_TIMER_FLAG_ONE_SHOT)) == RT_NULL)
{
- max.z = temp.z;
+ accel_debug("Accel err: Create timer failed!\n");
+ return -RT_ERROR;
}
- 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,
+ 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))
+ 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)
{
- rt_kprintf("Please calibrate the device first!\n");
- return;
+ 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;
+ }
}
- 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.)
+FINSH_FUNCTION_EXPORT(test_accel, list accelerometer info.)
#endif
#endif
diff --git a/bsp/efm32/dev_accel.h b/bsp/efm32/dev_accel.h
index 2950ce354d..9e2ba2ec18 100644
--- a/bsp/efm32/dev_accel.h
+++ b/bsp/efm32/dev_accel.h
@@ -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__ */
diff --git a/bsp/efm32/drv_iic.c b/bsp/efm32/drv_iic.c
index 081871ca6a..aefe41d327 100644
--- a/bsp/efm32/drv_iic.c
+++ b/bsp/efm32/drv_iic.c
@@ -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);
@@ -541,6 +539,22 @@ static rt_err_t rt_iic_control (
/***************************************************************************//**
* @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
*
* @details
@@ -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");
diff --git a/bsp/efm32/drv_iic.h b/bsp/efm32/drv_iic.h
index 8199c56eb6..53df7b42e4 100644
--- a/bsp/efm32/drv_iic.h
+++ b/bsp/efm32/drv_iic.h
@@ -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);
diff --git a/bsp/efm32/rtconfig.h b/bsp/efm32/rtconfig.h
index 4db20604ab..ec9579a998 100644
--- a/bsp/efm32/rtconfig.h
+++ b/bsp/efm32/rtconfig.h
@@ -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